From 530ec7ab24182395dc64b6548a886a00970c9d5a Mon Sep 17 00:00:00 2001 From: owen Date: Sat, 26 Aug 2023 22:29:56 +0800 Subject: [PATCH 01/15] =?UTF-8?q?mall:=20=E5=AE=8C=E5=96=84=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E5=8F=91=E9=80=81=E4=BC=98=E6=83=A0=E5=88=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/enums/ErrorCodeConstants.java | 6 +- .../enums/coupon/CouponTakeTypeEnum.java | 4 +- .../admin/coupon/CouponController.java | 8 ++ .../coupon/CouponTemplateController.java | 12 +++ .../admin/coupon/vo/coupon/CouponBaseVO.java | 2 +- .../coupon/vo/coupon/CouponSendReqVO.java | 24 ++++++ .../convert/coupon/CouponConvert.java | 29 +++++++ .../dal/dataobject/coupon/CouponDO.java | 2 +- .../dal/mysql/coupon/CouponMapper.java | 7 ++ .../mysql/coupon/CouponTemplateMapper.java | 28 ++++++ .../service/coupon/CouponService.java | 45 ++++++++++ .../service/coupon/CouponServiceImpl.java | 86 +++++++++++++++++++ .../service/coupon/CouponTemplateService.java | 16 +++- .../coupon/CouponTemplateServiceImpl.java | 9 +- 14 files changed, 271 insertions(+), 7 deletions(-) create mode 100644 yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponSendReqVO.java diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index e17f0de44..2b9ca9bc2 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -27,8 +27,12 @@ public interface ErrorCodeConstants { // ========== 优惠劵模板 1013004000 ========== ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1013004000, "优惠劵模板不存在"); ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1013004001, "发放数量不能小于已领取数量({})"); + ErrorCode COUPON_TEMPLATE_TASK_EMPTY = new ErrorCode(1013004002, "当前剩余数量不够领取"); + ErrorCode COUPON_TEMPLATE_USER_TASKED = new ErrorCode(1013004003, "用户已领取过此优惠券"); + ErrorCode COUPON_TEMPLATE_EXPIRED = new ErrorCode(1013004004, "优惠券已过期"); + ErrorCode COUPON_TEMPLATE_CANNOT_TAKE = new ErrorCode(1013004005, "领取方式不正确"); - // ========== 优惠劵模板 1013005000 ========== + // ========== 优惠劵 1013005000 ========== ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1013005000, "优惠券不存在"); ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1013005001, "回收优惠劵失败,优惠劵已被使用"); ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1013005002, "优惠劵不处于待使用状态"); diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java index ce7974142..c741b3885 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java @@ -14,9 +14,11 @@ import java.util.Arrays; @AllArgsConstructor @Getter public enum CouponTakeTypeEnum implements IntArrayValuable { - + COMMON(0, "通用"), BY_USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 BY_ADMIN(2, "指定发放"), // 后台指定会员赠送优惠劵 + BY_REGISTER(3, "新人券"), // 注册时自动领取 + BY_EXCHANGE(4, "兑换"), // 一般渠道券通过兑换领取 ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponTakeTypeEnum::getValue).toArray(); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java index e7780ca2a..6e02fef7f 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java @@ -8,6 +8,7 @@ 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.CouponPageItemRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponSendReqVO; 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.service.coupon.CouponService; @@ -72,4 +73,11 @@ public class CouponController { return success(pageResulVO); } + @PostMapping("/send") + @Operation(summary = "发送优惠劵") + @PreAuthorize("@ss.hasPermission('promotion:coupon:send')") + public CommonResult sendCoupon(@Valid @RequestBody CouponSendReqVO reqVO) { + Boolean result = couponService.sendCoupon(reqVO.getTemplateId(), reqVO.getUserIds()); + return success(result); + } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java index 1b1ae505c..c6ab43693 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java @@ -1,10 +1,12 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon; +import cn.hutool.core.collection.ListUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.*; 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.coupon.CouponTakeTypeEnum; import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -15,6 +17,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -76,4 +79,13 @@ public class CouponTemplateController { return success(CouponTemplateConvert.INSTANCE.convertPage(pageResult)); } + @GetMapping("/can-take-page") + @Operation(summary = "获得可用于领取的优惠劵模板分页") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:query')") + public CommonResult> getCanTakeCouponTemplatePage(@Valid CouponTemplatePageReqVO pageVO) { + List canTakeTypes = ListUtil.of(CouponTakeTypeEnum.COMMON.getValue(), CouponTakeTypeEnum.BY_ADMIN.getValue()); + PageResult pageResult = couponTemplateService.getCanTakeCouponTemplatePage(pageVO, canTakeTypes); + return success(CouponTemplateConvert.INSTANCE.convertPage(pageResult)); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java index 742c10cc7..32d861736 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java @@ -26,7 +26,7 @@ public class CouponBaseVO { // ========== 基本信息 BEGIN ========== @Schema(description = "优惠劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @NotNull(message = "优惠劵模板编号不能为空") - private Integer templateId; + private Long templateId; @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送") @NotNull(message = "优惠劵名不能为空") diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponSendReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponSendReqVO.java new file mode 100644 index 000000000..bac879f9c --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponSendReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Set; + +@Schema(description = "管理后台 - 优惠劵发放 Request VO") +@Data +@ToString(callSuper = true) +public class CouponSendReqVO { + + @Schema(description = "优惠劵模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "优惠劵模板编号不能为空") + private Long templateId; + + @Schema(description = "用户编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1, 2]") + @NotEmpty(message = "用户编号列表不能为空") + private Set userIds; + +} 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 7bfdca706..3ab2018f9 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 @@ -1,12 +1,18 @@ package cn.iocoder.yudao.module.promotion.convert.coupon; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.time.LocalDateTime; + /** * 优惠劵 Convert * @@ -21,4 +27,27 @@ public interface CouponConvert { CouponRespDTO convert(CouponDO bean); + default CouponDO convert(CouponTemplateDO template, Long userId) { + CouponDO couponDO = new CouponDO() + .setTemplateId(template.getId()) + .setName(template.getName()) + .setTakeType(template.getTakeType()) + .setUsePrice(template.getUsePrice()) + .setProductScope(template.getProductScope()) + .setProductSpuIds(template.getProductSpuIds()) + .setDiscountType(template.getDiscountType()) + .setDiscountPercent(template.getDiscountPercent()) + .setDiscountPrice(template.getDiscountPrice()) + .setDiscountLimitPrice(template.getDiscountLimitPrice()) + .setStatus(CouponStatusEnum.UNUSED.getStatus()) + .setUserId(userId); + if (CouponTemplateValidityTypeEnum.DATE.getType().equals(template.getValidityType())) { + couponDO.setValidStartTime(template.getValidStartTime()); + couponDO.setValidEndTime(template.getValidEndTime()); + } else if (CouponTemplateValidityTypeEnum.TERM.getType().equals(template.getValidityType())) { + couponDO.setValidStartTime(LocalDateTime.now().plusDays(template.getFixedStartTerm())); + couponDO.setValidEndTime(LocalDateTime.now().plusDays(template.getFixedEndTerm())); + } + return couponDO; + } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java index 7971392d4..bf2de3531 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java @@ -36,7 +36,7 @@ public class CouponDO extends BaseDO { * * 关联 {@link CouponTemplateDO#getId()} */ - private Integer templateId; + private Long templateId; /** * 优惠劵名 * 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 4417ae6e5..20fa28800 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 @@ -55,4 +55,11 @@ public interface CouponMapper extends BaseMapperX { .eq(CouponDO::getStatus, status)); } + default List selectByTemplateIdAndUserId(Long templateId, Collection userIds) { + return selectList(new LambdaQueryWrapperX() + .eq(CouponDO::getTemplateId, templateId) + .in(CouponDO::getUserId, userIds) + ); + } + } 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 7cea814af..0bef2d2ff 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 @@ -1,13 +1,19 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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.template.CouponTemplatePageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.function.Consumer; + /** * 优惠劵模板 Mapper * @@ -25,6 +31,28 @@ public interface CouponTemplateMapper extends BaseMapperX { .orderByDesc(CouponTemplateDO::getId)); } + default PageResult selectCanTakePage(CouponTemplatePageReqVO reqVO, Collection takeTypes) { + // 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴ + Consumer> canTakeConsumer = w -> + // 1.状态为可用的 + w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) + // 2.领取方式一致 + .in(CouponTemplateDO::getTakeType, takeTypes) + // 3.未过期 + .and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) + .or() + .gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now())) + // 4.剩余数量大于0 + .apply(" take_count < total_count "); + + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(CouponTemplateDO::getName, reqVO.getName()) + .eqIfPresent(CouponTemplateDO::getDiscountType, reqVO.getDiscountType()) + .betweenIfPresent(CouponTemplateDO::getCreateTime, reqVO.getCreateTime()) + .and(canTakeConsumer) + .orderByDesc(CouponTemplateDO::getId)); + } + void updateTakeCount(@Param("id") Long id, @Param("incrCount") Integer incrCount); } 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 5981f6ca9..37ad4666c 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 @@ -1,10 +1,13 @@ 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.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; import java.util.List; +import java.util.Set; /** * 优惠劵 Service 接口 @@ -75,4 +78,46 @@ public interface CouponService { */ Long getUnusedCouponCount(Long userId); + /** + * 领取优惠券 + * + * @param templateId 优惠券模板编号 + * @param userIds 用户编号列表 + * @param takType 领取方式 + * @return 领取结果 + */ + Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takType); + + /** + * 【管理员】 给用户发送优惠券 + * + * @param templateId 优惠券模板编号 + * @param userIds 用户编号列表 + * @return 发送结果 + */ + default Boolean sendCoupon(Long templateId, Set userIds) { + return takeCoupon(templateId, userIds, CouponTakeTypeEnum.BY_ADMIN); + } + + /** + * 【会员】 领取优惠券 + * + * @param templateId 优惠券模板编号 + * @param userId 用户编号 + * @return 发送结果 + */ + default Boolean receiveCoupon(Long templateId, Long userId) { + return takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_USER); + } + + /** + * 【系统】 给用户发送新人券 + * + * @param templateId 优惠券模板编号 + * @param userId 用户编号列表 + * @return 发送结果 + */ + default Boolean sendCoupon(Long templateId, Long userId) { + return takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_REGISTER); + } } 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 fb661241c..794fe2c5c 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 @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.promotion.service.coupon; +import cn.hutool.core.collection.CollStreamUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -9,9 +11,13 @@ 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.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.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 org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -19,7 +25,9 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.time.LocalDateTime; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; @@ -125,4 +133,82 @@ public class CouponServiceImpl implements CouponService { return couponMapper.selectCountByUserIdAndStatus(userId, CouponStatusEnum.UNUSED.getStatus()); } + @Override + public Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takType) { + CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); + // 校验并过滤用户 + userIds = validateAndFilterTakeUserId(template, userIds, takType); + + List couponList = userIds.stream() + .map(userId -> CouponConvert.INSTANCE.convert(template, userId)) + .collect(Collectors.toList()); + // 批量保存 + couponMapper.insertBatch(couponList); + + // 增加优惠劵模板的领取数量 + couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size()); + + return true; + } + + /** + * 校验优惠券模板, 并过滤不可以领取的用户 + * + * @param couponTemplate 优惠券模板 + * @param userIds 领取人列表 + * @param takeType 领取方式 + * @return 可领取此券的用户列表 + */ + private Set validateAndFilterTakeUserId(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { + // 校验模板 + if (couponTemplate == null) { + throw exception(COUPON_TEMPLATE_NOT_EXISTS); + } + + if (couponTemplate.getTotalCount() > 0) { + // 校验剩余数量 + if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { + throw exception(COUPON_TEMPLATE_TASK_EMPTY); + } + } + + // 校验"固定日期"的有效期类型是否过期 + if (CouponTemplateValidityTypeEnum.DATE.getType().equals(couponTemplate.getValidityType())) { + if (LocalDateTimeUtils.beforeNow(couponTemplate.getValidEndTime())) { + throw exception(COUPON_TEMPLATE_EXPIRED); + } + } + + // 校验领取方式 + if (!CouponTakeTypeEnum.COMMON.getValue().equals(couponTemplate.getTakeType())) { + if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) { + throw exception(COUPON_TEMPLATE_CANNOT_TAKE); + } + } + + // 获取领取过此券的用户 + List takedList = couponMapper.selectByTemplateIdAndUserId(couponTemplate.getId(), userIds); + + // 校验新人券 + if (CouponTakeTypeEnum.BY_REGISTER.equals(takeType)) { + if (!takedList.isEmpty()) { + throw exception(COUPON_TEMPLATE_USER_TASKED); + } + } + + // 校验领取数量限制 + if (couponTemplate.getTakeLimitCount() > 0) { + // 统计用户的领取数量 + Map userTakeCountMap = CollStreamUtil.groupBy(takedList, CouponDO::getUserId, Collectors.summingInt(c -> 1)); + //过滤掉达到领取数量限制的用户 + userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); + // 用户全部领取过此优惠券 + if (userIds.isEmpty()) { + throw exception(COUPON_TEMPLATE_USER_TASKED); + } + } + + return userIds; + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java index fdf018974..da48d7ba4 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.Cou import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import javax.validation.Valid; +import java.util.List; /** * 优惠劵模板 Service 接口 @@ -33,7 +34,7 @@ public interface CouponTemplateService { /** * 更新优惠劵模板的状态 * - * @param id 编号 + * @param id 编号 * @param status 状态 */ void updateCouponTemplateStatus(Long id, Integer status); @@ -61,10 +62,21 @@ public interface CouponTemplateService { */ PageResult getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO); + + /** + * 获得优惠劵模板分页 + * + * @param pageReqVO 分页查询 + * @param canTakeTypes 可领取的方式 + * @return 优惠劵模板分页 + */ + PageResult getCanTakeCouponTemplatePage(CouponTemplatePageReqVO pageReqVO, + List canTakeTypes); + /** * 更新优惠劵模板的领取数量 * - * @param id 优惠劵模板编号 + * @param id 优惠劵模板编号 * @param incrCount 增加数量 */ void updateCouponTemplateTakeCount(Long id, int incrCount); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java index 1a9cc8bfb..2de8b8948 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java @@ -12,9 +12,11 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL; /** * 优惠劵模板 Service 实现类 @@ -86,6 +88,11 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { return couponTemplateMapper.selectPage(pageReqVO); } + @Override + public PageResult getCanTakeCouponTemplatePage(CouponTemplatePageReqVO pageReqVO, List canTakeTypes) { + return couponTemplateMapper.selectCanTakePage(pageReqVO, canTakeTypes); + } + @Override public void updateCouponTemplateTakeCount(Long id, int incrCount) { couponTemplateMapper.updateTakeCount(id, incrCount); From 1f9968d78496fcb91a8d2f073f39fee11289ae8f Mon Sep 17 00:00:00 2001 From: puhui999 Date: Fri, 1 Sep 2023 12:12:15 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E8=AE=A2=E5=8D=95=E4=B8=AD=E5=BF=83?= =?UTF-8?q?=EF=BC=9A=E4=BF=AE=E6=94=B9=E8=8E=B7=E5=8F=96=E5=94=AE=E5=90=8E?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E8=AF=A6=E6=83=85=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=AE=A2=E5=8D=95=E7=AE=A1=E7=90=86=E5=90=8E?= =?UTF-8?q?=E5=8F=B0=E7=89=A9=E6=B5=81=E8=8E=B7=E5=8F=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../aftersale/TradeAfterSaleController.java | 20 ++++++++++++++++++ .../admin/order/TradeOrderController.java | 12 ++--------- .../order/vo/TradeOrderDetailRespVO.java | 21 +++++++++++++++++++ .../admin/order/vo/TradeOrderPageReqVO.java | 2 +- .../aftersale/TradeAfterSaleConvert.java | 6 ++++-- .../convert/order/TradeOrderConvert.java | 18 +++++++++++++--- .../service/order/TradeOrderQueryService.java | 10 ++++++++- .../order/TradeOrderQueryServiceImpl.java | 21 +++++++++++++++++++ 8 files changed, 93 insertions(+), 17 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java index 56fdc06da..689f3540b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.java @@ -27,6 +27,8 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.annotation.security.PermitAll; import javax.validation.Valid; +import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -82,6 +84,24 @@ public class TradeAfterSaleController { MemberUserRespDTO user = memberUserApi.getUser(afterSale.getUserId()); // 获取售后日志 List logs = afterSaleLogService.getLog(afterSale.getId()); + // TODO 方便测试看效果,review 后移除 + if (logs == null) { + logs = new ArrayList<>(); + } + for (int i = 1; i <= 6; i++) { + TradeAfterSaleLogRespDTO respVO = new TradeAfterSaleLogRespDTO(); + respVO.setId((long) i); + respVO.setUserId((long) i); + respVO.setUserType(1); + respVO.setAfterSaleId(id); + respVO.setOrderId((long) i); + respVO.setOrderItemId((long) i); + respVO.setBeforeStatus((i - 1) * 10); + respVO.setAfterStatus(i * 10); + respVO.setContent("66+6"); + respVO.setCreateTime(LocalDateTime.now()); + logs.add(respVO); + } return success(TradeAfterSaleConvert.INSTANCE.convert(afterSale, order, orderItems, user, logs)); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java index 57b21bee0..926c2408c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java @@ -25,7 +25,6 @@ import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - 交易订单") @RestController @@ -70,7 +69,7 @@ public class TradeOrderController { TradeOrderDO order = tradeOrderQueryService.getOrder(id); // 查询订单项 List orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id); - + // orderLog // 拼接数据 MemberUserRespDTO user = memberUserApi.getUser(order.getUserId()); return success(TradeOrderConvert.INSTANCE.convert(order, orderItems, user)); @@ -82,7 +81,7 @@ public class TradeOrderController { @PreAuthorize("@ss.hasPermission('trade:order:query')") public CommonResult> getOrderExpressTrackList(@RequestParam("id") Long id) { return success(TradeOrderConvert.INSTANCE.convertList02( - tradeOrderQueryService.getExpressTrackList(id, getLoginUserId()))); + tradeOrderQueryService.getExpressTrackList(id))); } @PutMapping("/delivery") @@ -117,11 +116,4 @@ public class TradeOrderController { return success(true); } - // TODO @puhui999 订单物流详情 - // TODO @puhui999 【前台】订单取消 - // TODO @puhui999 【后台】订单取消 - // TODO @puhui999 【前台】订单核销 - // TODO @puhui999 【前台】订单删除 - // TODO @puhui999 【后台】订单统计 - } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java index ae135c95e..dd84a3ad6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.Prod import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.time.LocalDateTime; import java.util.List; @Schema(description = "管理后台 - 交易订单的详情 Response VO") @@ -24,6 +25,26 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO { */ private MemberUserRespVO user; + /** + * TODO 订单操作日志, 先模拟一波 + */ + private List orderLog; + + @Data + public static class OrderLog { + + /** + * 内容 + */ + private String content; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + } + @Schema(description = "管理后台 - 交易订单的详情的订单项目") @Data public static class Item extends TradeOrderItemBaseVO { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java index 33c4cc400..58361379c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderPageReqVO.java @@ -61,5 +61,5 @@ public class TradeOrderPageReqVO extends PageParam { @Schema(description = "订单来源", example = "10") @InEnum(value = TerminalEnum.class, message = "订单来源 {value}") private Integer terminal; - +// TODO 添加配送方式筛选 } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java index 4d83fe147..d4f481c37 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/aftersale/TradeAfterSaleConvert.java @@ -72,16 +72,18 @@ public interface TradeAfterSaleConvert { default TradeAfterSaleDetailRespVO convert(TradeAfterSaleDO afterSale, TradeOrderDO order, List orderItems, MemberUserRespDTO user, List logs) { - TradeAfterSaleDetailRespVO respVO = convert(afterSale, orderItems, convertList1(logs)); + TradeAfterSaleDetailRespVO respVO = convert(afterSale, orderItems); // 处理用户信息 respVO.setUser(convert(user)); // 处理订单信息 respVO.setOrder(convert(order)); + // 处理售后日志 + respVO.setAfterSaleLog(convertList1(logs)); return respVO; } List convertList1(List list); @Mapping(target = "id", source = "afterSale.id") - TradeAfterSaleDetailRespVO convert(TradeAfterSaleDO afterSale, List orderItems, List logs); + TradeAfterSaleDetailRespVO convert(TradeAfterSaleDO afterSale, List orderItems); TradeOrderBaseVO convert(TradeOrderDO order); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 0285a6354..a928bb9a5 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.trade.convert.order; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; @@ -37,8 +36,10 @@ import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; -import java.util.*; -import java.util.stream.Collectors; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; @@ -86,7 +87,9 @@ public interface TradeOrderConvert { default ProductSkuUpdateStockReqDTO convert(List list) { return new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(list)); } + List convertList(List list); + @Mappings({ @Mapping(source = "skuId", target = "id"), @Mapping(source = "count", target = "incrCount"), @@ -137,6 +140,15 @@ public interface TradeOrderConvert { orderVO.setReceiverAreaName(AreaUtils.format(order.getReceiverAreaId())); // 处理用户信息 orderVO.setUser(convert(user)); + // TODO puhui999:模拟订单操作日志 + ArrayList orderLogs = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + TradeOrderDetailRespVO.OrderLog orderLog = new TradeOrderDetailRespVO.OrderLog(); + orderLog.setContent("订单操作" + i); + orderLog.setCreateTime(LocalDateTime.now()); + orderLogs.add(orderLog); + } + orderVO.setOrderLog(orderLogs); return orderVO; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java index 0c03802a3..0cd5240bd 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryService.java @@ -66,7 +66,7 @@ public interface TradeOrderQueryService { Long getOrderCount(Long userId, Integer status, Boolean commonStatus); /** - * 获得订单的物流轨迹 + * 【前台】获得订单的物流轨迹 * * @param id 订单编号 * @param userId 用户编号 @@ -74,6 +74,14 @@ public interface TradeOrderQueryService { */ List getExpressTrackList(Long id, Long userId); + /** + * 【后台】获得订单的物流轨迹 + * + * @param id 订单编号 + * @return 物流轨迹数组 + */ + List getExpressTrackList(Long id); + // =================== Order Item =================== /** diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java index 9fb238465..3cf2c17f6 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java @@ -106,6 +106,27 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { throw exception(ORDER_NOT_FOUND); } + return getTrackRespDTOs(order); + } + + @Override + public List getExpressTrackList(Long id) { + // 查询订单 + TradeOrderDO order = tradeOrderMapper.selectById(id); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + + return getTrackRespDTOs(order); + } + + /** + * 得到物流轨迹 + * + * @param order 订单 + * @return 物流轨迹 + */ + private List getTrackRespDTOs(TradeOrderDO order) { // 查询物流公司 if (order.getLogisticsId() == null) { return Collections.emptyList(); From dd6adb8ee6f431d062dc826971711066675f6f86 Mon Sep 17 00:00:00 2001 From: "zhijiantianya@gmail.com" Date: Fri, 1 Sep 2023 19:08:27 +0800 Subject: [PATCH 03/15] code review order --- .../AppDeliverPickUpStoreController.java | 2 + .../app/order/AppTradeOrderController.java | 7 ++- .../dataobject/order/TradeOrderItemDO.java | 2 + .../aftersale/TradeAfterSaleServiceImpl.java | 2 + .../order/TradeOrderUpdateServiceImpl.java | 53 ++++++++++++------- .../service/price/TradePriceServiceImpl.java | 1 + .../TradeDeliveryPriceCalculator.java | 1 + 7 files changed, 46 insertions(+), 22 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverPickUpStoreController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverPickUpStoreController.java index 275eacde8..3b49fb6ae 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverPickUpStoreController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/delivery/AppDeliverPickUpStoreController.java @@ -24,6 +24,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @Validated public class AppDeliverPickUpStoreController { + // TODO 待实现[门店自提]:如果 latitude、longitude 非空,计算经纬度,并排序。计算的库,可以使用 hutool 的 DistanceUtil 计算。 @GetMapping("/list") @Operation(summary = "获得自提门店列表") public CommonResult> getDeliveryPickUpStoreList( @@ -50,6 +51,7 @@ public class AppDeliverPickUpStoreController { return success(list); } + // TODO 待实现[门店自提]: @GetMapping("/get") @Operation(summary = "获得自提门店") @Parameter(name = "id", description = "门店编号") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index e3205fcaf..92181fca7 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -49,9 +49,6 @@ public class AppTradeOrderController { @Resource private DeliveryExpressService deliveryExpressService; - @Resource - private ProductPropertyValueApi productPropertyValueApi; - @Resource private TradeOrderProperties tradeOrderProperties; @@ -78,6 +75,7 @@ public class AppTradeOrderController { return success(true); } + // TODO @芋艿:如果拼团活动、秒杀活动、砍价活动时,是不是要额外在返回活动之类的信息; @GetMapping("/get-detail") @Operation(summary = "获得交易订单") @Parameter(name = "id", description = "交易订单编号") @@ -93,6 +91,7 @@ public class AppTradeOrderController { // 查询物流公司 DeliveryExpressDO express = order.getLogisticsId() != null && order.getLogisticsId() > 0 ? deliveryExpressService.getDeliveryExpress(order.getLogisticsId()) : null; + // TODO @puhui999:如果门店自提,信息的拼接; // 最终组合 return success(TradeOrderConvert.INSTANCE.convert02(order, orderItems, tradeOrderProperties, express)); } @@ -141,7 +140,7 @@ public class AppTradeOrderController { @PutMapping("/receive") @Operation(summary = "确认交易订单收货") @Parameter(name = "id", description = "交易订单编号") - public CommonResult takeOrder(@RequestParam("id") Long id) { + public CommonResult receiveOrder(@RequestParam("id") Long id) { tradeOrderUpdateService.receiveOrder(getLoginUserId(), id); return success(true); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java index f078f149e..27dd13f67 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java @@ -143,6 +143,8 @@ public class TradeOrderItemDO extends BaseDO { * 对应 taobao 的 trade.point_fee 字段 */ private Integer pointPrice; + // TODO @芋艿:如果商品 vip 折扣时,到底是新增一个 vipPrice 记录优惠记录,还是 vipDiscountPrice,记录 vip 的优惠;还是直接使用 vipPrice; + // 目前 crmeb 的选择,单独一个 vipPrice 记录优惠价格;感觉不一定合理,可以在看看有赞的; // ========== 售后基本信息 ========== diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceImpl.java index 83a180fc5..eae983799 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 @@ -98,6 +98,8 @@ public class TradeAfterSaleServiceImpl implements TradeAfterSaleService, AfterSa return afterSale; } + // TODO 芋艿:拼团失败,要不要发起售后的方式退款?还是走取消逻辑? + @Override @Transactional(rollbackFor = Exception.class) public Long createAfterSale(Long userId, AppTradeAfterSaleCreateReqVO createReqVO) { 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 41da62dab..0776e4beb 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 @@ -96,6 +96,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { private TradePriceService tradePriceService; @Resource private DeliveryExpressService deliveryExpressService; + @Resource + private TradeMessageService tradeMessageService; @Resource private ProductSkuApi productSkuApi; @@ -105,27 +107,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { private AddressApi addressApi; @Resource private CouponApi couponApi; - + @Resource + private CombinationRecordApi combinationRecordApi; + @Resource + private BargainRecordApi bargainRecordApi; @Resource private MemberUserApi memberUserApi; @Resource private MemberLevelApi memberLevelApi; @Resource private MemberPointApi memberPointApi; - @Resource private ProductCommentApi productCommentApi; - @Resource - private TradeMessageService tradeMessageService; + @Resource private TradeOrderProperties tradeOrderProperties; - @Resource - private CombinationRecordApi combinationRecordApi; - - @Resource - private BargainRecordApi bargainRecordApi; - // =================== Order =================== @Override @@ -179,15 +176,17 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { @Override @Transactional(rollbackFor = Exception.class) public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { - // 2. 价格计算 + // 1. 价格计算 TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); - // 3.1 插入 TradeOrderDO 订单 + + // 2.1 插入 TradeOrderDO 订单 TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO); - // 3.2 插入 TradeOrderItemDO 订单项 + // 2.2 插入 TradeOrderItemDO 订单项 List orderItems = createTradeOrderItems(order, calculateRespBO); - // 订单创建完后的逻辑 + + // 3. 订单创建完后的逻辑 afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO); - // 3.3 校验订单类型 + // 3.1 拼团的特殊逻辑 // TODO @puhui999:这个逻辑,先抽个小方法;未来要通过设计模式,把这些拼团之类的逻辑,抽象出去 // 拼团 if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) { @@ -205,15 +204,21 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user)); } + // 3.2 秒杀的特殊逻辑 // TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除 if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) { } + // 3.3 砍价的特殊逻辑 // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! return order; } + // TODO @puhui999:订单超时,自动取消; + + // TODO @疯狂:用户手动取消订单; + /** * 校验收件地址是否存在 * @@ -239,7 +244,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { } TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address); order.setType(validateActivity(createReqVO)); - order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; + order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈; order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); @@ -251,6 +256,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // 退款信息 order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); tradeOrderMapper.insert(order); + // TODO @puhui999:如果是门店订单,则需要生成核销码; return order; } @@ -291,6 +297,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { TradeOrderDO tradeOrderDO, List orderItems, TradePriceCalculateRespBO calculateRespBO) { // 下单时扣减商品库存 + // TODO @puhui999:扣库存,需要前置; + // 1)如果是秒杀商品:额外扣减秒杀的库存; + // 2)如果是拼团活动:额外扣减拼团的库存; + // 3)如果是砍价活动:额外扣减砍价的库存; productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); // 删除购物车商品 @@ -299,9 +309,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { cartService.deleteCart(userId, cartIds); } - // 扣减积分 TODO 芋艿:待实现 + // 扣减积分 TODO 芋艿:待实现,需要前置; - // 有使用优惠券时更新 + // 有使用优惠券时更新 TODO 芋艿:需要前置; if (createReqVO.getCouponId() != null) { couponApi.useCoupon(new CouponUseReqDTO().setId(createReqVO.getCouponId()).setUserId(userId) .setOrderId(tradeOrderDO.getId())); @@ -510,6 +520,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // TODO 芋艿:lili 发送订单变化的消息 // TODO 芋艿:lili 发送商品被购买完成的数据 + + // TODO 芋艿:销售佣金的记录; + + // TODO 芋艿:获得积分; } @Override @@ -529,11 +543,13 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { if (order.getPayStatus()) { throw exception(ORDER_UPDATE_PRICE_FAIL_PAID); } + // TODO @puhui999:如果改价,需要校验下是否真的变化; // 更新 // TODO @puhui999:TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下; TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO); update.setPayPrice(update.getPayPrice() + update.getAdjustPrice()); + // TODO @芋艿:改价时,赠送的积分,要不要做改动??? tradeOrderMapper.updateById(update); } @@ -651,6 +667,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { List orderItems = tradeOrderItemMapper.selectListByOrderId(order.getId()); if (!anyMatch(orderItems, item -> Objects.equals(item.getCommentStatus(), Boolean.FALSE))) { tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE)); + // TODO 待实现:已完成评价,要不要写一条订单日志?目前 crmeb 会写,有赞可以研究下 } return comment; } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java index a6982c177..e211374bf 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java @@ -41,6 +41,7 @@ public class TradePriceServiceImpl implements TradePriceService { @Resource private List priceCalculators; + // TODO @疯狂:需要搞个 TradePriceCalculator,计算赠送积分; @Override public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { // 1.1 获得商品 SKU 数组 diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java index 35a3cb92a..5454c450d 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java @@ -42,6 +42,7 @@ public class TradeDeliveryPriceCalculator implements TradePriceCalculator { @Override public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { + // TODO @芋艿:如果门店自提,需要校验是否开启; // 1.1 判断配送方式 if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { return; From 28adfff10edc93b372fd1785c0cb0862599f57b5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 1 Sep 2023 20:00:04 +0800 Subject: [PATCH 04/15] =?UTF-8?q?code=20review=EF=BC=9A=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/order/vo/TradeOrderDetailRespVO.java | 3 ++- .../trade/service/order/TradeOrderQueryServiceImpl.java | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java index dd84a3ad6..fa1e77d0e 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/vo/TradeOrderDetailRespVO.java @@ -26,10 +26,11 @@ public class TradeOrderDetailRespVO extends TradeOrderBaseVO { private MemberUserRespVO user; /** - * TODO 订单操作日志, 先模拟一波 + * TODO 订单操作日志, 先模拟一波;返回 logs,简洁,然后复数哈 */ private List orderLog; + // TODO @puhui999:swagger 注解 @Data public static class OrderLog { diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java index 3cf2c17f6..657c6f0f8 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderQueryServiceImpl.java @@ -106,7 +106,7 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { throw exception(ORDER_NOT_FOUND); } - return getTrackRespDTOs(order); + return getExpressTrackList(order); } @Override @@ -117,16 +117,16 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService { throw exception(ORDER_NOT_FOUND); } - return getTrackRespDTOs(order); + return getExpressTrackList(order); } /** - * 得到物流轨迹 + * 获得订单的物流轨迹 * * @param order 订单 * @return 物流轨迹 */ - private List getTrackRespDTOs(TradeOrderDO order) { + private List getExpressTrackList(TradeOrderDO order) { // 查询物流公司 if (order.getLogisticsId() == null) { return Collections.emptyList(); From b3fcefa677bda5be09a6e44647daa3abb75d5b5d Mon Sep 17 00:00:00 2001 From: owen Date: Fri, 1 Sep 2023 20:37:20 +0800 Subject: [PATCH 05/15] =?UTF-8?q?trade:=20=E4=BC=9A=E5=91=98=E5=8F=96?= =?UTF-8?q?=E6=B6=88=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/api/coupon/CouponApi.java | 6 +++ .../promotion/enums/ErrorCodeConstants.java | 1 + .../promotion/api/coupon/CouponApiImpl.java | 5 +++ .../service/coupon/CouponService.java | 6 +++ .../service/coupon/CouponServiceImpl.java | 23 +++++++++++ .../trade/enums/ErrorCodeConstants.java | 1 + .../app/order/AppTradeOrderController.java | 2 +- .../convert/order/TradeOrderConvert.java | 6 +++ .../order/TradeOrderUpdateService.java | 7 ++++ .../order/TradeOrderUpdateServiceImpl.java | 39 ++++++++++++++++++- 10 files changed, 93 insertions(+), 3 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java index ce7a712da..71e3ca18b 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java @@ -28,4 +28,10 @@ public interface CouponApi { */ CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index e17f0de44..5c98d04e9 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -33,6 +33,7 @@ public interface ErrorCodeConstants { ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1013005001, "回收优惠劵失败,优惠劵已被使用"); ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1013005002, "优惠劵不处于待使用状态"); ErrorCode COUPON_VALID_TIME_NOT_NOW = new ErrorCode(1013005003, "优惠券不在使用时间范围内"); + ErrorCode COUPON_STATUS_NOT_USED = new ErrorCode(1013005004, "优惠劵不是已使用状态"); // ========== 满减送活动 1013006000 ========== ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1013006000, "满减送活动不存在"); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java index a06ab57cd..d9ecc7d9c 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java @@ -34,4 +34,9 @@ public class CouponApiImpl implements CouponApi { return CouponConvert.INSTANCE.convert(coupon); } + @Override + public void returnUsedCoupon(Long id) { + couponService.returnUsedCoupon(id); + } + } 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 5981f6ca9..4c3b659fa 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 @@ -75,4 +75,10 @@ public interface CouponService { */ Long getUnusedCouponCount(Long userId); + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); } 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 fb661241c..9754f6fd5 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 @@ -125,4 +125,27 @@ public class CouponServiceImpl implements CouponService { return couponMapper.selectCountByUserIdAndStatus(userId, CouponStatusEnum.UNUSED.getStatus()); } + @Override + public void returnUsedCoupon(Long id) { + // 校验存在 + CouponDO coupon = couponMapper.selectById(id); + if (coupon == null) { + throw exception(COUPON_NOT_EXISTS); + } + + // 校验状态 + if (!CouponStatusEnum.USED.getStatus().equals(coupon.getStatus())) { + throw exception(COUPON_STATUS_NOT_USED); + } + + // 退还 + Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) + // 退还时可能已经过期了 + ? CouponStatusEnum.EXPIRE.getStatus() + : CouponStatusEnum.UNUSED.getStatus(); + couponMapper.updateById(new CouponDO().setId(id).setStatus(status)); + + // TODO 增加优惠券变动记录? + } + } diff --git a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java index 3aa0e5dd3..40f604e94 100644 --- a/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java @@ -33,6 +33,7 @@ public interface ErrorCodeConstants { ErrorCode ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000022, "交易订单发货失败,拼团未成功"); ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功"); ErrorCode ORDER_DELIVERY_FAIL_DELIVERY_TYPE_NOT_EXPRESS = new ErrorCode(1011000024, "交易订单发货失败,发货类型不是快递"); + ErrorCode ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID = new ErrorCode(1011000025, "交易订单取消失败,订单不是【待支付】状态"); // ========== After Sale 模块 1011000100 ========== ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在"); diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index e3205fcaf..a28815df7 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -150,7 +150,7 @@ public class AppTradeOrderController { @Operation(summary = "取消交易订单") @Parameter(name = "id", description = "交易订单编号") public CommonResult cancelOrder(@RequestParam("id") Long id) { - // TODO @芋艿:未实现,mock 用 + tradeOrderUpdateService.cancelOrder(getLoginUserId(), id); return success(true); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java index 0285a6354..e3a6e84be 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java @@ -86,6 +86,12 @@ public interface TradeOrderConvert { default ProductSkuUpdateStockReqDTO convert(List list) { return new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(list)); } + + default ProductSkuUpdateStockReqDTO convertNegative(List list) { + List items = TradeOrderConvert.INSTANCE.convertList(list); + items.forEach(item -> item.setIncrCount(-item.getIncrCount())); + return new ProductSkuUpdateStockReqDTO(items); + } List convertList(List list); @Mappings({ @Mapping(source = "skuId", target = "id"), 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 bf52358e6..ee9128b6c 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 @@ -117,4 +117,11 @@ public interface TradeOrderUpdateService { */ Long createOrderItemComment(Long userId, AppTradeOrderItemCommentCreateReqVO createReqVO); + /** + * 【会员】取消订单 + * + * @param userId 用户ID + * @param id 订单编号 + */ + void cancelOrder(Long userId, 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 41da62dab..900b8ccc4 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 @@ -291,7 +291,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { TradeOrderDO tradeOrderDO, List orderItems, TradePriceCalculateRespBO calculateRespBO) { // 下单时扣减商品库存 - productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems)); // 删除购物车商品 Set cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId); @@ -299,7 +299,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { cartService.deleteCart(userId, cartIds); } - // 扣减积分 TODO 芋艿:待实现 + // 扣减积分 TODO 芋艿:待实现, 这个是不是应该放到支付成功之后? // 有使用优惠券时更新 if (createReqVO.getCouponId() != null) { @@ -655,6 +655,41 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { return comment; } + @Override + public void cancelOrder(Long userId, Long id) { + // 校验存在 + TradeOrderDO order = tradeOrderMapper.selectOrderByIdAndUserId(id, userId); + if (order == null) { + throw exception(ORDER_NOT_FOUND); + } + // 校验状态 + if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) { + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); + } + + // 1.更新 TradeOrderDO 状态为已取消 + int updateCount = tradeOrderMapper.updateByIdAndStatus(id, order.getStatus(), + new TradeOrderDO().setStatus(TradeOrderStatusEnum.CANCELED.getStatus()) + .setCancelTime(LocalDateTime.now()) + .setCancelType(TradeOrderCancelTypeEnum.MEMBER_CANCEL.getType())); + if (updateCount == 0) { + throw exception(ORDER_CANCEL_FAIL_STATUS_NOT_UNPAID); + } + + // 2.回滚库存 + List orderItems = tradeOrderItemMapper.selectListByOrderId(id); + productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convert(orderItems)); + + // 3.回滚优惠券 + couponApi.returnUsedCoupon(order.getCouponId()); + + // 4.回滚积分:积分是支付成功后才增加的吧? + + // TODO 芋艿:OrderLog + + // TODO 芋艿:lili 发送订单变化的消息 + } + /** * 判断指定订单的所有订单项,是不是都售后成功 * From 76f510f2471a6996d0bcabb13036a8d57edeca97 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 1 Sep 2023 22:51:28 +0800 Subject: [PATCH 06/15] =?UTF-8?q?code=20review=EF=BC=9A=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E5=8A=B5=E5=8F=91=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/enums/ErrorCodeConstants.java | 4 +- .../enums/coupon/CouponTakeTypeEnum.java | 3 +- .../admin/coupon/CouponController.java | 6 +-- .../coupon/CouponTemplateController.java | 1 + .../convert/coupon/CouponConvert.java | 1 - .../dal/mysql/coupon/CouponMapper.java | 1 + .../mysql/coupon/CouponTemplateMapper.java | 16 ++---- .../service/coupon/CouponService.java | 12 +++-- .../service/coupon/CouponServiceImpl.java | 51 ++++++++----------- 9 files changed, 43 insertions(+), 52 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index 2b9ca9bc2..3103b8f30 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -27,8 +27,8 @@ public interface ErrorCodeConstants { // ========== 优惠劵模板 1013004000 ========== ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1013004000, "优惠劵模板不存在"); ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1013004001, "发放数量不能小于已领取数量({})"); - ErrorCode COUPON_TEMPLATE_TASK_EMPTY = new ErrorCode(1013004002, "当前剩余数量不够领取"); - ErrorCode COUPON_TEMPLATE_USER_TASKED = new ErrorCode(1013004003, "用户已领取过此优惠券"); + ErrorCode COUPON_TEMPLATE_NOT_ENOUGH = new ErrorCode(1013004002, "当前剩余数量不够领取"); + ErrorCode COUPON_TEMPLATE_USER_ALREADY_TAKE = new ErrorCode(1013004003, "用户已领取过此优惠券"); ErrorCode COUPON_TEMPLATE_EXPIRED = new ErrorCode(1013004004, "优惠券已过期"); ErrorCode COUPON_TEMPLATE_CANNOT_TAKE = new ErrorCode(1013004005, "领取方式不正确"); diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java index c741b3885..bf79e9ae0 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java @@ -14,7 +14,8 @@ import java.util.Arrays; @AllArgsConstructor @Getter public enum CouponTakeTypeEnum implements IntArrayValuable { - COMMON(0, "通用"), + + COMMON(0, "通用"), // TODO @疯狂:要不去掉“通用"和“兑换”,保持和 crmeb 一致;就手动领取、指定发送、新人券 BY_USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 BY_ADMIN(2, "指定发放"), // 后台指定会员赠送优惠劵 BY_REGISTER(3, "新人券"), // 注册时自动领取 diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java index 6e02fef7f..b9d8dbc23 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java @@ -22,7 +22,6 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; import java.util.Map; -import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @@ -65,9 +64,9 @@ public class CouponController { if (CollUtil.isEmpty(pageResulVO.getList())) { return success(pageResulVO); } + // 读取用户信息,进行拼接 - Set userIds = convertSet(pageResult.getList(), CouponDO::getUserId); - Map userMap = memberUserApi.getUserMap(userIds); + Map userMap = memberUserApi.getUserMap(convertSet(pageResult.getList(), CouponDO::getUserId)); pageResulVO.getList().forEach(itemRespVO -> MapUtils.findAndThen(userMap, itemRespVO.getUserId(), userRespDTO -> itemRespVO.setNickname(userRespDTO.getNickname()))); return success(pageResulVO); @@ -80,4 +79,5 @@ public class CouponController { Boolean result = couponService.sendCoupon(reqVO.getTemplateId(), reqVO.getUserIds()); return success(result); } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java index c6ab43693..f1aaf82a1 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java @@ -79,6 +79,7 @@ public class CouponTemplateController { return success(CouponTemplateConvert.INSTANCE.convertPage(pageResult)); } + // TODO @疯狂:是不是可以合并到 getCouponTemplatePage 接口,作为一个参数选择 @GetMapping("/can-take-page") @Operation(summary = "获得可用于领取的优惠劵模板分页") @PreAuthorize("@ss.hasPermission('promotion:coupon-template:query')") 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 3ab2018f9..7060f0da5 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 @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.promotion.convert.coupon; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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; 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 20fa28800..52be9b47a 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 @@ -55,6 +55,7 @@ public interface CouponMapper extends BaseMapperX { .eq(CouponDO::getStatus, status)); } + // TODO @疯狂:要 selectList 哈; default List selectByTemplateIdAndUserId(Long templateId, Collection userIds) { return selectList(new LambdaQueryWrapperX() .eq(CouponDO::getTemplateId, templateId) 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 0bef2d2ff..241a961d9 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 @@ -34,17 +34,11 @@ public interface CouponTemplateMapper extends BaseMapperX { default PageResult selectCanTakePage(CouponTemplatePageReqVO reqVO, Collection takeTypes) { // 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴ Consumer> canTakeConsumer = w -> - // 1.状态为可用的 - w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) - // 2.领取方式一致 - .in(CouponTemplateDO::getTakeType, takeTypes) - // 3.未过期 - .and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) - .or() - .gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now())) - // 4.剩余数量大于0 - .apply(" take_count < total_count "); - + w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的 + .in(CouponTemplateDO::getTakeType, takeTypes) // 2. 领取方式一致 + .and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) // 3. 未过期 + .or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now())) + .apply(" take_count < total_count "); // 4. 剩余数量大于 0 return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(CouponTemplateDO::getName, reqVO.getName()) .eqIfPresent(CouponTemplateDO::getDiscountType, reqVO.getDiscountType()) 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 37ad4666c..4fd3ec845 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 @@ -78,18 +78,20 @@ public interface CouponService { */ Long getUnusedCouponCount(Long userId); + // TODO @疯狂:可以返回 void;因为都是 true = = /** * 领取优惠券 * * @param templateId 优惠券模板编号 * @param userIds 用户编号列表 - * @param takType 领取方式 + * @param takeType 领取方式 * @return 领取结果 */ - Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takType); + Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType); + // TODO @疯狂:感觉 3 个方法的命名,改成 takeCouponByAdmin;takeCouponByUser;takeCouponByRegister 会更容易理解哈;现在两个都叫 sendCoupon ,感觉不太好懂 /** - * 【管理员】 给用户发送优惠券 + * 【管理员】给用户发送优惠券 * * @param templateId 优惠券模板编号 * @param userIds 用户编号列表 @@ -100,7 +102,7 @@ public interface CouponService { } /** - * 【会员】 领取优惠券 + * 【会员】领取优惠券 * * @param templateId 优惠券模板编号 * @param userId 用户编号 @@ -111,7 +113,7 @@ public interface CouponService { } /** - * 【系统】 给用户发送新人券 + * 【系统】给用户发送新人券 * * @param templateId 优惠券模板编号 * @param userId 用户编号列表 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 794fe2c5c..cc6b16f47 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 @@ -134,20 +134,20 @@ public class CouponServiceImpl implements CouponService { } @Override - public Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takType) { + public Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { + // 1. 校验并过滤用户 CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); - // 校验并过滤用户 - userIds = validateAndFilterTakeUserId(template, userIds, takType); + userIds = validateAndFilterTakeUserId(template, userIds, takeType); + // 2. 批量保存优惠劵 + // TODO @疯狂:这里可以使用 CollectionUtils.convertList 更简洁;stream 可以简化很多代码,常用的 stream 操作,使用 util 可以进一步简洁,同时提升可读性 List couponList = userIds.stream() .map(userId -> CouponConvert.INSTANCE.convert(template, userId)) .collect(Collectors.toList()); - // 批量保存 couponMapper.insertBatch(couponList); - // 增加优惠劵模板的领取数量 + // 3. 增加优惠劵模板的领取数量 couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size()); - return true; } @@ -159,55 +159,48 @@ public class CouponServiceImpl implements CouponService { * @param takeType 领取方式 * @return 可领取此券的用户列表 */ + // TODO @疯狂:我建议哈,校验模版,和过滤用户分成两个方法;混在一起,有点小重,后续单测可能也比较难写哈; private Set validateAndFilterTakeUserId(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { - // 校验模板 + // 1.1 校验模板 if (couponTemplate == null) { throw exception(COUPON_TEMPLATE_NOT_EXISTS); } - - if (couponTemplate.getTotalCount() > 0) { - // 校验剩余数量 - if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { - throw exception(COUPON_TEMPLATE_TASK_EMPTY); - } + // 1.2 校验剩余数量 + if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { + throw exception(COUPON_TEMPLATE_NOT_ENOUGH); } - - // 校验"固定日期"的有效期类型是否过期 + // 1.3 校验"固定日期"的有效期类型是否过期 if (CouponTemplateValidityTypeEnum.DATE.getType().equals(couponTemplate.getValidityType())) { if (LocalDateTimeUtils.beforeNow(couponTemplate.getValidEndTime())) { throw exception(COUPON_TEMPLATE_EXPIRED); } } - - // 校验领取方式 + // 1.4 校验领取方式 + // TODO @疯狂:如果要做这样的判断,使用 !ObjectUtils.equalsAny() 会更简洁 if (!CouponTakeTypeEnum.COMMON.getValue().equals(couponTemplate.getTakeType())) { if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) { throw exception(COUPON_TEMPLATE_CANNOT_TAKE); } } - // 获取领取过此券的用户 - List takedList = couponMapper.selectByTemplateIdAndUserId(couponTemplate.getId(), userIds); - + // 2.1 过滤掉,已经领取到上限的用户 + List alreadyTakeCoupons = couponMapper.selectByTemplateIdAndUserId(couponTemplate.getId(), userIds); // 校验新人券 + // TODO @疯狂:我在想,这个判断,是不是和下面的 couponTemplate.getTakeLimitCount() > 0 冗余了;可以先都过滤,然后最终去判断 userIds 是不是空了; if (CouponTakeTypeEnum.BY_REGISTER.equals(takeType)) { - if (!takedList.isEmpty()) { - throw exception(COUPON_TEMPLATE_USER_TASKED); + if (!alreadyTakeCoupons.isEmpty()) { + throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); } } - // 校验领取数量限制 if (couponTemplate.getTakeLimitCount() > 0) { - // 统计用户的领取数量 - Map userTakeCountMap = CollStreamUtil.groupBy(takedList, CouponDO::getUserId, Collectors.summingInt(c -> 1)); - //过滤掉达到领取数量限制的用户 + Map userTakeCountMap = CollStreamUtil.groupBy(alreadyTakeCoupons, CouponDO::getUserId, Collectors.summingInt(c -> 1)); userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); - // 用户全部领取过此优惠券 + // 2.2 如果所有用户都领取过,则抛出异常 if (userIds.isEmpty()) { - throw exception(COUPON_TEMPLATE_USER_TASKED); + throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); } } - return userIds; } From 3fbce643ee6f4e1cdcc871dd3b2608d518e4c0c2 Mon Sep 17 00:00:00 2001 From: owen Date: Fri, 1 Sep 2023 23:45:50 +0800 Subject: [PATCH 07/15] =?UTF-8?q?mall:=20=E5=8F=91=E9=80=81=E4=BC=98?= =?UTF-8?q?=E6=83=A0=E5=88=B8=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enums/coupon/CouponTakeTypeEnum.java | 2 - .../admin/coupon/CouponController.java | 4 +- .../coupon/CouponTemplateController.java | 14 ---- .../vo/template/CouponTemplatePageReqVO.java | 3 + .../dal/mysql/coupon/CouponMapper.java | 3 +- .../mysql/coupon/CouponTemplateMapper.java | 30 ++++----- .../service/coupon/CouponService.java | 22 +++---- .../service/coupon/CouponServiceImpl.java | 66 ++++++++----------- .../service/coupon/CouponTemplateService.java | 12 ---- .../coupon/CouponTemplateServiceImpl.java | 6 -- .../order/TradeOrderUpdateServiceImpl.java | 2 - 11 files changed, 55 insertions(+), 109 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java index bf79e9ae0..50263c6ce 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java @@ -15,11 +15,9 @@ import java.util.Arrays; @Getter public enum CouponTakeTypeEnum implements IntArrayValuable { - COMMON(0, "通用"), // TODO @疯狂:要不去掉“通用"和“兑换”,保持和 crmeb 一致;就手动领取、指定发送、新人券 BY_USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 BY_ADMIN(2, "指定发放"), // 后台指定会员赠送优惠劵 BY_REGISTER(3, "新人券"), // 注册时自动领取 - BY_EXCHANGE(4, "兑换"), // 一般渠道券通过兑换领取 ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponTakeTypeEnum::getValue).toArray(); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java index b9d8dbc23..c5460c348 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java @@ -76,8 +76,8 @@ public class CouponController { @Operation(summary = "发送优惠劵") @PreAuthorize("@ss.hasPermission('promotion:coupon:send')") public CommonResult sendCoupon(@Valid @RequestBody CouponSendReqVO reqVO) { - Boolean result = couponService.sendCoupon(reqVO.getTemplateId(), reqVO.getUserIds()); - return success(result); + couponService.takeCouponByAdmin(reqVO.getTemplateId(), reqVO.getUserIds()); + return success(true); } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java index f1aaf82a1..69e39d13c 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java @@ -1,12 +1,10 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon; -import cn.hutool.core.collection.ListUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.*; 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.coupon.CouponTakeTypeEnum; import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -17,7 +15,6 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; -import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -78,15 +75,4 @@ public class CouponTemplateController { PageResult pageResult = couponTemplateService.getCouponTemplatePage(pageVO); return success(CouponTemplateConvert.INSTANCE.convertPage(pageResult)); } - - // TODO @疯狂:是不是可以合并到 getCouponTemplatePage 接口,作为一个参数选择 - @GetMapping("/can-take-page") - @Operation(summary = "获得可用于领取的优惠劵模板分页") - @PreAuthorize("@ss.hasPermission('promotion:coupon-template:query')") - public CommonResult> getCanTakeCouponTemplatePage(@Valid CouponTemplatePageReqVO pageVO) { - List canTakeTypes = ListUtil.of(CouponTakeTypeEnum.COMMON.getValue(), CouponTakeTypeEnum.BY_ADMIN.getValue()); - PageResult pageResult = couponTemplateService.getCanTakeCouponTemplatePage(pageVO, canTakeTypes); - return success(CouponTemplateConvert.INSTANCE.convertPage(pageResult)); - } - } 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 e78d0140f..a95265100 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 @@ -8,6 +8,7 @@ import lombok.ToString; import org.springframework.format.annotation.DateTimeFormat; import java.time.LocalDateTime; +import java.util.List; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; @@ -30,4 +31,6 @@ public class CouponTemplatePageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; + @Schema(description = "可以领取的类型", example = "[1,2]") + private List canTakeTypes; } 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 52be9b47a..ddf90691c 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 @@ -55,8 +55,7 @@ public interface CouponMapper extends BaseMapperX { .eq(CouponDO::getStatus, status)); } - // TODO @疯狂:要 selectList 哈; - default List selectByTemplateIdAndUserId(Long templateId, Collection userIds) { + default List selectListByTemplateIdAndUserId(Long templateId, Collection userIds) { return selectList(new LambdaQueryWrapperX() .eq(CouponDO::getTemplateId, templateId) .in(CouponDO::getUserId, userIds) 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 241a961d9..25833ff1b 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 @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; @@ -11,7 +12,6 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import java.time.LocalDateTime; -import java.util.Collection; import java.util.function.Consumer; /** @@ -23,27 +23,23 @@ import java.util.function.Consumer; public interface CouponTemplateMapper extends BaseMapperX { default PageResult selectPage(CouponTemplatePageReqVO reqVO) { + Consumer> canTakeConsumer = null; + if (CollUtil.isNotEmpty(reqVO.getCanTakeTypes())) { + // 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴ + canTakeConsumer = w -> + w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的 + .in(CouponTemplateDO::getTakeType, reqVO.getCanTakeTypes()) // 2. 领取方式一致 + .and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) // 3. 未过期 + .or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now())) + .apply(" take_count < total_count "); // 4. 剩余数量大于 0 + } + return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(CouponTemplateDO::getName, reqVO.getName()) .eqIfPresent(CouponTemplateDO::getStatus, reqVO.getStatus()) .eqIfPresent(CouponTemplateDO::getDiscountType, reqVO.getDiscountType()) .betweenIfPresent(CouponTemplateDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(CouponTemplateDO::getId)); - } - - default PageResult selectCanTakePage(CouponTemplatePageReqVO reqVO, Collection takeTypes) { - // 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴ - Consumer> canTakeConsumer = w -> - w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的 - .in(CouponTemplateDO::getTakeType, takeTypes) // 2. 领取方式一致 - .and(ww -> ww.isNull(CouponTemplateDO::getValidEndTime) // 3. 未过期 - .or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now())) - .apply(" take_count < total_count "); // 4. 剩余数量大于 0 - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(CouponTemplateDO::getName, reqVO.getName()) - .eqIfPresent(CouponTemplateDO::getDiscountType, reqVO.getDiscountType()) - .betweenIfPresent(CouponTemplateDO::getCreateTime, reqVO.getCreateTime()) - .and(canTakeConsumer) + .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/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 4fd3ec845..11e3fa826 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 @@ -78,27 +78,23 @@ public interface CouponService { */ Long getUnusedCouponCount(Long userId); - // TODO @疯狂:可以返回 void;因为都是 true = = /** * 领取优惠券 * * @param templateId 优惠券模板编号 * @param userIds 用户编号列表 - * @param takeType 领取方式 - * @return 领取结果 + * @param takeType 领取方式 */ - Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType); + void takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType); - // TODO @疯狂:感觉 3 个方法的命名,改成 takeCouponByAdmin;takeCouponByUser;takeCouponByRegister 会更容易理解哈;现在两个都叫 sendCoupon ,感觉不太好懂 /** * 【管理员】给用户发送优惠券 * * @param templateId 优惠券模板编号 * @param userIds 用户编号列表 - * @return 发送结果 */ - default Boolean sendCoupon(Long templateId, Set userIds) { - return takeCoupon(templateId, userIds, CouponTakeTypeEnum.BY_ADMIN); + default void takeCouponByAdmin(Long templateId, Set userIds) { + takeCoupon(templateId, userIds, CouponTakeTypeEnum.BY_ADMIN); } /** @@ -106,10 +102,9 @@ public interface CouponService { * * @param templateId 优惠券模板编号 * @param userId 用户编号 - * @return 发送结果 */ - default Boolean receiveCoupon(Long templateId, Long userId) { - return takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_USER); + default void takeCouponByUser(Long templateId, Long userId) { + takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_USER); } /** @@ -117,9 +112,8 @@ public interface CouponService { * * @param templateId 优惠券模板编号 * @param userId 用户编号列表 - * @return 发送结果 */ - default Boolean sendCoupon(Long templateId, Long userId) { - return takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_REGISTER); + default void takeCouponByRegister(Long templateId, Long userId) { + takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_REGISTER); } } 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 cc6b16f47..b0ffc1749 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 @@ -30,6 +30,7 @@ import java.util.Set; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static java.util.Arrays.asList; @@ -134,74 +135,63 @@ public class CouponServiceImpl implements CouponService { } @Override - public Boolean takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { - // 1. 校验并过滤用户 + public void takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); - userIds = validateAndFilterTakeUserId(template, userIds, takeType); + // 1. 过滤掉达到领取限制的用户 + removeTakeLimitUserId(template, userIds); + // 2. 校验用户 + validateCanTake(template, userIds, takeType); - // 2. 批量保存优惠劵 - // TODO @疯狂:这里可以使用 CollectionUtils.convertList 更简洁;stream 可以简化很多代码,常用的 stream 操作,使用 util 可以进一步简洁,同时提升可读性 - List couponList = userIds.stream() - .map(userId -> CouponConvert.INSTANCE.convert(template, userId)) - .collect(Collectors.toList()); - couponMapper.insertBatch(couponList); + // 3. 批量保存优惠劵 + couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId))); // 3. 增加优惠劵模板的领取数量 couponTemplateService.updateCouponTemplateTakeCount(templateId, userIds.size()); - return true; } /** - * 校验优惠券模板, 并过滤不可以领取的用户 + * 校验优惠券是否可以领取 * * @param couponTemplate 优惠券模板 * @param userIds 领取人列表 * @param takeType 领取方式 - * @return 可领取此券的用户列表 */ - // TODO @疯狂:我建议哈,校验模版,和过滤用户分成两个方法;混在一起,有点小重,后续单测可能也比较难写哈; - private Set validateAndFilterTakeUserId(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { - // 1.1 校验模板 + private void validateCanTake(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { + // 如果所有用户都领取过,则抛出异常 + if (userIds.isEmpty()) { + throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); + } + + // 校验模板 if (couponTemplate == null) { throw exception(COUPON_TEMPLATE_NOT_EXISTS); } - // 1.2 校验剩余数量 + // 校验剩余数量 if (couponTemplate.getTakeCount() + userIds.size() > couponTemplate.getTotalCount()) { throw exception(COUPON_TEMPLATE_NOT_ENOUGH); } - // 1.3 校验"固定日期"的有效期类型是否过期 + // 校验"固定日期"的有效期类型是否过期 if (CouponTemplateValidityTypeEnum.DATE.getType().equals(couponTemplate.getValidityType())) { if (LocalDateTimeUtils.beforeNow(couponTemplate.getValidEndTime())) { throw exception(COUPON_TEMPLATE_EXPIRED); } } - // 1.4 校验领取方式 - // TODO @疯狂:如果要做这样的判断,使用 !ObjectUtils.equalsAny() 会更简洁 - if (!CouponTakeTypeEnum.COMMON.getValue().equals(couponTemplate.getTakeType())) { - if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) { - throw exception(COUPON_TEMPLATE_CANNOT_TAKE); - } - } - // 2.1 过滤掉,已经领取到上限的用户 - List alreadyTakeCoupons = couponMapper.selectByTemplateIdAndUserId(couponTemplate.getId(), userIds); - // 校验新人券 - // TODO @疯狂:我在想,这个判断,是不是和下面的 couponTemplate.getTakeLimitCount() > 0 冗余了;可以先都过滤,然后最终去判断 userIds 是不是空了; - if (CouponTakeTypeEnum.BY_REGISTER.equals(takeType)) { - if (!alreadyTakeCoupons.isEmpty()) { - throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); - } + // 校验领取方式 + if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) { + throw exception(COUPON_TEMPLATE_CANNOT_TAKE); } - // 校验领取数量限制 + } + + private void removeTakeLimitUserId(CouponTemplateDO couponTemplate, Set userIds) { + // 查询已领过券的用户 + List alreadyTakeCoupons = couponMapper.selectListByTemplateIdAndUserId(couponTemplate.getId(), userIds); + + // 移除达到领取限制的用户 if (couponTemplate.getTakeLimitCount() > 0) { Map userTakeCountMap = CollStreamUtil.groupBy(alreadyTakeCoupons, CouponDO::getUserId, Collectors.summingInt(c -> 1)); userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); - // 2.2 如果所有用户都领取过,则抛出异常 - if (userIds.isEmpty()) { - throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); - } } - return userIds; } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java index da48d7ba4..9f2d925a2 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.Cou import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import javax.validation.Valid; -import java.util.List; /** * 优惠劵模板 Service 接口 @@ -62,17 +61,6 @@ public interface CouponTemplateService { */ PageResult getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO); - - /** - * 获得优惠劵模板分页 - * - * @param pageReqVO 分页查询 - * @param canTakeTypes 可领取的方式 - * @return 优惠劵模板分页 - */ - PageResult getCanTakeCouponTemplatePage(CouponTemplatePageReqVO pageReqVO, - List canTakeTypes); - /** * 更新优惠劵模板的领取数量 * diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java index 2de8b8948..a5be46746 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java @@ -12,7 +12,6 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_TEMPLATE_NOT_EXISTS; @@ -88,11 +87,6 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { return couponTemplateMapper.selectPage(pageReqVO); } - @Override - public PageResult getCanTakeCouponTemplatePage(CouponTemplatePageReqVO pageReqVO, List canTakeTypes) { - return couponTemplateMapper.selectCanTakePage(pageReqVO, canTakeTypes); - } - @Override public void updateCouponTemplateTakeCount(Long id, int incrCount) { couponTemplateMapper.updateTakeCount(id, incrCount); 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 0776e4beb..1242dfdee 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 @@ -217,8 +217,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // TODO @puhui999:订单超时,自动取消; - // TODO @疯狂:用户手动取消订单; - /** * 校验收件地址是否存在 * From a6ec3fefcf1d9174be7f273f63c7019829ceb827 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 2 Sep 2023 00:31:23 +0800 Subject: [PATCH 08/15] =?UTF-8?q?code=20review=EF=BC=9A=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E5=8A=B5=E5=8F=91=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/PromotionProductScopeEnum.java | 5 ++-- .../enums/coupon/CouponTakeTypeEnum.java | 6 ++-- .../vo/template/CouponTemplatePageReqVO.java | 6 +++- .../mysql/coupon/CouponTemplateMapper.java | 4 +-- .../service/coupon/CouponService.java | 6 ++-- .../service/coupon/CouponServiceImpl.java | 28 ++++++++++++------- 6 files changed, 34 insertions(+), 21 deletions(-) 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 0a7a4994d..6ae9f9f46 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,8 +15,9 @@ import java.util.Arrays; @AllArgsConstructor public enum PromotionProductScopeEnum implements IntArrayValuable { - ALL(1, "全部商品参与"), - SPU(2, "指定商品参与"), + 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-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java index 50263c6ce..1513e62ea 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java @@ -15,9 +15,9 @@ import java.util.Arrays; @Getter public enum CouponTakeTypeEnum implements IntArrayValuable { - BY_USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 - BY_ADMIN(2, "指定发放"), // 后台指定会员赠送优惠劵 - BY_REGISTER(3, "新人券"), // 注册时自动领取 + USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 + ADMIN(2, "指定发放"), // 后台指定会员赠送优惠劵 + REGISTER(3, "新人券"), // 注册时自动领取 ; public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponTakeTypeEnum::getValue).toArray(); 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 a95265100..abc7134e1 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 @@ -1,6 +1,8 @@ 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.coupon.CouponTakeTypeEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -31,6 +33,8 @@ public class CouponTemplatePageReqVO extends PageParam { @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) private LocalDateTime[] createTime; - @Schema(description = "可以领取的类型", example = "[1,2]") + @Schema(description = "可以领取的类型", example = "[1,2, 3]") + @InEnum(value = CouponTakeTypeEnum.class, message = "可以领取的类型,必须是 {value}") private List canTakeTypes; + } 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 25833ff1b..c95513e18 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 @@ -23,9 +23,9 @@ import java.util.function.Consumer; public interface CouponTemplateMapper extends BaseMapperX { default PageResult selectPage(CouponTemplatePageReqVO reqVO) { + // 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴ Consumer> canTakeConsumer = null; if (CollUtil.isNotEmpty(reqVO.getCanTakeTypes())) { - // 构建可领取的查询条件, 好啰嗦 ( ╯-_-)╯┴—┴ canTakeConsumer = w -> w.eq(CouponTemplateDO::getStatus, CommonStatusEnum.ENABLE.getStatus()) // 1. 状态为可用的 .in(CouponTemplateDO::getTakeType, reqVO.getCanTakeTypes()) // 2. 领取方式一致 @@ -33,7 +33,7 @@ public interface CouponTemplateMapper extends BaseMapperX { .or().gt(CouponTemplateDO::getValidEndTime, LocalDateTime.now())) .apply(" take_count < total_count "); // 4. 剩余数量大于 0 } - + // 执行分页查询 return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(CouponTemplateDO::getName, reqVO.getName()) .eqIfPresent(CouponTemplateDO::getStatus, reqVO.getStatus()) 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 11e3fa826..17f922ae8 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 @@ -94,7 +94,7 @@ public interface CouponService { * @param userIds 用户编号列表 */ default void takeCouponByAdmin(Long templateId, Set userIds) { - takeCoupon(templateId, userIds, CouponTakeTypeEnum.BY_ADMIN); + takeCoupon(templateId, userIds, CouponTakeTypeEnum.ADMIN); } /** @@ -104,7 +104,7 @@ public interface CouponService { * @param userId 用户编号 */ default void takeCouponByUser(Long templateId, Long userId) { - takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_USER); + takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.USER); } /** @@ -114,6 +114,6 @@ public interface CouponService { * @param userId 用户编号列表 */ default void takeCouponByRegister(Long templateId, Long userId) { - takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.BY_REGISTER); + takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER); } } 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 b0ffc1749..66aa9e7d8 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 @@ -138,8 +138,8 @@ public class CouponServiceImpl implements CouponService { public void takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); // 1. 过滤掉达到领取限制的用户 - removeTakeLimitUserId(template, userIds); - // 2. 校验用户 + removeTakeLimitUserId(userIds, template); + // 2. 校验优惠劵是否可以领取 validateCanTake(template, userIds, takeType); // 3. 批量保存优惠劵 @@ -158,7 +158,7 @@ public class CouponServiceImpl implements CouponService { */ private void validateCanTake(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { // 如果所有用户都领取过,则抛出异常 - if (userIds.isEmpty()) { + if (CollUtil.isEmpty(userIds)) { throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); } @@ -176,22 +176,30 @@ public class CouponServiceImpl implements CouponService { throw exception(COUPON_TEMPLATE_EXPIRED); } } - // 校验领取方式 if (ObjectUtil.notEqual(couponTemplate.getTakeType(), takeType.getValue())) { throw exception(COUPON_TEMPLATE_CANNOT_TAKE); } } - private void removeTakeLimitUserId(CouponTemplateDO couponTemplate, Set userIds) { + /** + * 过滤掉达到领取上线的用户 + * + * @param userIds 用户编号数组 + * @param couponTemplate 优惠劵模版 + */ + private void removeTakeLimitUserId(Set userIds, CouponTemplateDO couponTemplate) { + if (couponTemplate.getTakeLimitCount() <= 0) { + return; + } // 查询已领过券的用户 List alreadyTakeCoupons = couponMapper.selectListByTemplateIdAndUserId(couponTemplate.getId(), userIds); - - // 移除达到领取限制的用户 - if (couponTemplate.getTakeLimitCount() > 0) { - Map userTakeCountMap = CollStreamUtil.groupBy(alreadyTakeCoupons, CouponDO::getUserId, Collectors.summingInt(c -> 1)); - userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); + if (CollUtil.isEmpty(alreadyTakeCoupons)) { + return; } + // 移除达到领取限制的用户 + Map userTakeCountMap = CollStreamUtil.groupBy(alreadyTakeCoupons, CouponDO::getUserId, Collectors.summingInt(c -> 1)); + userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); } } From 68c1113ed1dad674de647a1c99a68e18f45da16e Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 2 Sep 2023 00:32:16 +0800 Subject: [PATCH 09/15] =?UTF-8?q?code=20review=EF=BC=9A=E4=BC=98=E6=83=A0?= =?UTF-8?q?=E5=8A=B5=E5=8F=91=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/service/coupon/CouponServiceImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 66aa9e7d8..115818548 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 @@ -138,9 +138,9 @@ public class CouponServiceImpl implements CouponService { public void takeCoupon(Long templateId, Set userIds, CouponTakeTypeEnum takeType) { CouponTemplateDO template = couponTemplateService.getCouponTemplate(templateId); // 1. 过滤掉达到领取限制的用户 - removeTakeLimitUserId(userIds, template); + removeTakeLimitUser(userIds, template); // 2. 校验优惠劵是否可以领取 - validateCanTake(template, userIds, takeType); + validateCouponTemplateCanTake(template, userIds, takeType); // 3. 批量保存优惠劵 couponMapper.insertBatch(convertList(userIds, userId -> CouponConvert.INSTANCE.convert(template, userId))); @@ -156,7 +156,7 @@ public class CouponServiceImpl implements CouponService { * @param userIds 领取人列表 * @param takeType 领取方式 */ - private void validateCanTake(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { + private void validateCouponTemplateCanTake(CouponTemplateDO couponTemplate, Set userIds, CouponTakeTypeEnum takeType) { // 如果所有用户都领取过,则抛出异常 if (CollUtil.isEmpty(userIds)) { throw exception(COUPON_TEMPLATE_USER_ALREADY_TAKE); @@ -188,7 +188,7 @@ public class CouponServiceImpl implements CouponService { * @param userIds 用户编号数组 * @param couponTemplate 优惠劵模版 */ - private void removeTakeLimitUserId(Set userIds, CouponTemplateDO couponTemplate) { + private void removeTakeLimitUser(Set userIds, CouponTemplateDO couponTemplate) { if (couponTemplate.getTakeLimitCount() <= 0) { return; } From c25bf38f50eb8d9917faa7db4754723793e8acb5 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 2 Sep 2023 00:52:31 +0800 Subject: [PATCH 10/15] =?UTF-8?q?code=20review=EF=BC=9A=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E7=9A=84=E5=8F=96=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../promotion/api/coupon/CouponApi.java | 13 +++--- .../promotion/api/coupon/CouponApiImpl.java | 10 ++-- .../service/coupon/CouponService.java | 13 +++--- .../service/coupon/CouponServiceImpl.java | 46 +++++++++---------- .../order/TradeOrderUpdateServiceImpl.java | 2 +- 5 files changed, 43 insertions(+), 41 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java index 71e3ca18b..ab970c0a3 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApi.java @@ -20,6 +20,13 @@ public interface CouponApi { */ void useCoupon(@Valid CouponUseReqDTO useReqDTO); + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); + /** * 校验优惠劵 * @@ -28,10 +35,4 @@ public interface CouponApi { */ CouponRespDTO validateCoupon(@Valid CouponValidReqDTO validReqDTO); - /** - * 退还已使用的优惠券 - * - * @param id 优惠券编号 - */ - void returnUsedCoupon(Long id); } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java index d9ecc7d9c..94d00e35c 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/CouponApiImpl.java @@ -28,15 +28,15 @@ public class CouponApiImpl implements CouponApi { useReqDTO.getOrderId()); } + @Override + public void returnUsedCoupon(Long id) { + couponService.returnUsedCoupon(id); + } + @Override public CouponRespDTO validateCoupon(CouponValidReqDTO validReqDTO) { CouponDO coupon = couponService.validCoupon(validReqDTO.getId(), validReqDTO.getUserId()); return CouponConvert.INSTANCE.convert(coupon); } - @Override - public void returnUsedCoupon(Long id) { - couponService.returnUsedCoupon(id); - } - } 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 bfe42f363..cf22fe2b3 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 @@ -54,6 +54,13 @@ public interface CouponService { */ void useCoupon(Long id, Long userId, Long orderId); + /** + * 退还已使用的优惠券 + * + * @param id 优惠券编号 + */ + void returnUsedCoupon(Long id); + /** * 回收优惠劵 * @@ -117,10 +124,4 @@ public interface CouponService { takeCoupon(templateId, CollUtil.newHashSet(userId), CouponTakeTypeEnum.REGISTER); } - /** - * 退还已使用的优惠券 - * - * @param id 优惠券编号 - */ - void returnUsedCoupon(Long id); } 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 5e608e696..9abbd3c5f 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 @@ -102,6 +102,29 @@ public class CouponServiceImpl implements CouponService { } } + @Override + public void returnUsedCoupon(Long id) { + // 校验存在 + CouponDO coupon = couponMapper.selectById(id); + if (coupon == null) { + throw exception(COUPON_NOT_EXISTS); + } + // 校验状态 + if (ObjectUtil.notEqual(coupon.getTemplateId(), CouponStatusEnum.USED.getStatus())) { + throw exception(COUPON_STATUS_NOT_USED); + } + + // 退还 + // TODO @疯狂:最好 where status,避免可能存在的并发问题 + Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) + // 退还时可能已经过期了 + ? CouponStatusEnum.EXPIRE.getStatus() + : CouponStatusEnum.UNUSED.getStatus(); + couponMapper.updateById(new CouponDO().setId(id).setStatus(status)); + + // TODO 增加优惠券变动记录? + } + @Override @Transactional public void deleteCoupon(Long id) { @@ -202,27 +225,4 @@ public class CouponServiceImpl implements CouponService { userIds.removeIf(userId -> MapUtil.getInt(userTakeCountMap, userId, 0) >= couponTemplate.getTakeLimitCount()); } - @Override - public void returnUsedCoupon(Long id) { - // 校验存在 - CouponDO coupon = couponMapper.selectById(id); - if (coupon == null) { - throw exception(COUPON_NOT_EXISTS); - } - - // 校验状态 - if (!CouponStatusEnum.USED.getStatus().equals(coupon.getStatus())) { - throw exception(COUPON_STATUS_NOT_USED); - } - - // 退还 - Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) - // 退还时可能已经过期了 - ? CouponStatusEnum.EXPIRE.getStatus() - : CouponStatusEnum.UNUSED.getStatus(); - couponMapper.updateById(new CouponDO().setId(id).setStatus(status)); - - // TODO 增加优惠券变动记录? - } - } 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 4c88226ea..f887b71e8 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 @@ -699,7 +699,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService { // 3.回滚优惠券 couponApi.returnUsedCoupon(order.getCouponId()); - // 4.回滚积分:积分是支付成功后才增加的吧? + // 4.回滚积分:积分是支付成功后才增加的吧? 回复:每个项目不同,目前看下来,确认收货貌似更合适,我再看看其它项目的业务选择; // TODO 芋艿:OrderLog From 11ad7ad5e43c21f24d2bba44041ebc252d8a4aa6 Mon Sep 17 00:00:00 2001 From: owen Date: Sat, 2 Sep 2023 07:44:16 +0800 Subject: [PATCH 11/15] =?UTF-8?q?mall:=20=E4=BC=98=E6=83=A0=E5=88=B8?= =?UTF-8?q?=E9=80=80=E8=BF=98=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/promotion/service/coupon/CouponServiceImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 9abbd3c5f..4192126ad 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 @@ -115,12 +115,14 @@ public class CouponServiceImpl implements CouponService { } // 退还 - // TODO @疯狂:最好 where status,避免可能存在的并发问题 Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) // 退还时可能已经过期了 ? CouponStatusEnum.EXPIRE.getStatus() : CouponStatusEnum.UNUSED.getStatus(); - couponMapper.updateById(new CouponDO().setId(id).setStatus(status)); + int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(), new CouponDO().setStatus(status)); + if (updateCount == 0) { + throw exception(COUPON_STATUS_NOT_USED); + } // TODO 增加优惠券变动记录? } From 6a7be19d3a401f5138d899570c79c5e5ec708849 Mon Sep 17 00:00:00 2001 From: owen Date: Sat, 2 Sep 2023 08:44:02 +0800 Subject: [PATCH 12/15] =?UTF-8?q?common:=20=E5=A2=9E=E5=8A=A0InEnumCollect?= =?UTF-8?q?ionValidator=EF=BC=8C=E7=94=A8=E4=BA=8E=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E6=9E=9A=E4=B8=BE=E5=80=BC=E5=88=97=E8=A1=A8=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E7=9A=84=E5=8F=96=E5=80=BC=E8=8C=83=E5=9B=B4=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=9C=89=E4=87=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/common/validation/InEnum.java | 2 +- .../validation/InEnumCollectionValidator.java | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java index c2d56b0c5..139b08965 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java @@ -17,7 +17,7 @@ import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint( - validatedBy = InEnumValidator.class + validatedBy = {InEnumValidator.class, InEnumCollectionValidator.class} ) public @interface InEnum { diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java new file mode 100644 index 000000000..d20a71703 --- /dev/null +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnumCollectionValidator.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.framework.common.validation; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class InEnumCollectionValidator implements ConstraintValidator> { + + private List values; + + @Override + public void initialize(InEnum annotation) { + IntArrayValuable[] values = annotation.value().getEnumConstants(); + if (values.length == 0) { + this.values = Collections.emptyList(); + } else { + this.values = Arrays.stream(values[0].array()).boxed().collect(Collectors.toList()); + } + } + + @Override + public boolean isValid(Collection list, ConstraintValidatorContext context) { + // 校验通过 + if (CollUtil.containsAll(values, list)) { + return true; + } + // 校验不通过,自定义提示语句(因为,注解上的 value 是枚举类,无法获得枚举类的实际值) + context.disableDefaultConstraintViolation(); // 禁用默认的 message 的值 + context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate() + .replaceAll("\\{value}", CollUtil.join(list, ","))).addConstraintViolation(); // 重新添加错误提示语句 + return false; + } + +} + From 8bbaaf1ce9e3a2bf360cd7577e61c5ccb89a377f Mon Sep 17 00:00:00 2001 From: owen Date: Sat, 2 Sep 2023 09:53:37 +0800 Subject: [PATCH 13/15] =?UTF-8?q?promotion:=20=E4=BC=98=E6=83=A0=E5=88=B8?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=20productSpuIds=20=E6=94=B9=E6=88=90=20produ?= =?UTF-8?q?ctScopeValues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/promotion/api/coupon/dto/CouponRespDTO.java | 4 ++-- .../admin/coupon/vo/coupon/CouponBaseVO.java | 4 ++-- .../admin/coupon/vo/template/CouponTemplateBaseVO.java | 10 +++++----- .../coupon/vo/template/AppCouponTemplateRespVO.java | 4 ++-- .../module/promotion/convert/coupon/CouponConvert.java | 2 +- .../promotion/dal/dataobject/coupon/CouponDO.java | 6 +++--- .../dal/dataobject/coupon/CouponTemplateDO.java | 4 ++-- .../price/calculator/TradeCouponPriceCalculator.java | 2 +- .../calculator/TradeCouponPriceCalculatorTest.java | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java index 34031e604..a404bf27d 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/coupon/dto/CouponRespDTO.java @@ -71,9 +71,9 @@ public class CouponRespDTO { */ private Integer productScope; /** - * 商品 SPU 编号的数组 + * 商品范围编号的数组 */ - private List productSpuIds; + private List productScopeValues; // ========== 使用规则 END ========== // ========== 使用效果 BEGIN ========== diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java index 32d861736..0d7459867 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java @@ -67,8 +67,8 @@ public class CouponBaseVO { @InEnum(PromotionProductScopeEnum.class) private Integer productScope; - @Schema(description = "商品 SPU 编号的数组", example = "1,3") - private List productSpuIds; + @Schema(description = "商品范围编号的数组", example = "1,3") + private List productScopeValues; // ========== 使用规则 END ========== // ========== 使用效果 BEGIN ========== diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java index 7c1855d38..dff0d8d78 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java @@ -54,8 +54,8 @@ public class CouponTemplateBaseVO { @InEnum(PromotionProductScopeEnum.class) private Integer productScope; - @Schema(description = "商品 SPU 编号的数组", example = "1,3") - private List productSpuIds; + @Schema(description = "商品范围编号的数组", example = "1,3") + private List productScopeValues; @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "生效日期类型不能为空") @@ -95,11 +95,11 @@ public class CouponTemplateBaseVO { @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用 private Integer discountLimitPrice; - @AssertTrue(message = "商品 SPU 编号的数组不能为空") + @AssertTrue(message = "商品范围编号的数组不能为空") @JsonIgnore - public boolean isProductSpuIdsValid() { + public boolean isProductScopeValuesValid() { return Objects.equals(productScope, PromotionProductScopeEnum.ALL.getScope()) // 全部范围时,可以为空 - || CollUtil.isNotEmpty(productSpuIds); + || CollUtil.isNotEmpty(productScopeValues); } @AssertTrue(message = "生效开始时间不能为空") diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java index 83410fd89..7dd0042ed 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/template/AppCouponTemplateRespVO.java @@ -28,8 +28,8 @@ public class AppCouponTemplateRespVO { // @InEnum(PromotionProductScopeEnum.class) // private Integer productScope; // -// @Schema(description = "商品 SPU 编号的数组", example = "1,3") -// private List productSpuIds; +// @Schema(description = "商品范围编号的数组", example = "1,3") +// private List productScopeValues; @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer validityType; 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 7060f0da5..364095a4d 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 @@ -33,7 +33,7 @@ public interface CouponConvert { .setTakeType(template.getTakeType()) .setUsePrice(template.getUsePrice()) .setProductScope(template.getProductScope()) - .setProductSpuIds(template.getProductSpuIds()) + .setProductScopeValues(template.getProductScopeValues()) .setDiscountType(template.getDiscountType()) .setDiscountPercent(template.getDiscountPercent()) .setDiscountPrice(template.getDiscountPrice()) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java index bf2de3531..b98615093 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java @@ -89,12 +89,12 @@ public class CouponDO extends BaseDO { */ private Integer productScope; /** - * 商品 SPU 编号的数组 + * 商品范围编号的数组 * - * 冗余 {@link CouponTemplateDO#getProductSpuIds()} + * 冗余 {@link CouponTemplateDO#getProductScopeValues()} */ @TableField(typeHandler = LongListTypeHandler.class) - private List productSpuIds; + private List productScopeValues; // ========== 使用规则 END ========== // ========== 使用效果 BEGIN ========== diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java index 93f9ace35..6cab9c58c 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java @@ -85,10 +85,10 @@ public class CouponTemplateDO extends BaseDO { */ private Integer productScope; /** - * 商品 SPU 编号的数组 + * 商品范围编号的数组 */ @TableField(typeHandler = LongListTypeHandler.class) - private List productSpuIds; + private List productScopeValues; /** * 生效日期类型 * diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java index f00b04b12..96db8175c 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java @@ -102,7 +102,7 @@ public class TradeCouponPriceCalculator implements TradePriceCalculator { Predicate matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected; if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) { matchPredicate = matchPredicate // 额外加如下条件 - .and(orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId())); + .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getSpuId())); } return filterList(result.getItems(), matchPredicate); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java index ac4872c86..94ac66c9b 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java @@ -65,7 +65,7 @@ public class TradeCouponPriceCalculatorTest extends BaseMockitoUnitTest { // mock 方法(优惠劵 Coupon 信息) CouponRespDTO coupon = randomPojo(CouponRespDTO.class, o -> o.setId(1024L).setName("程序员节") - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L)) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductScopeValues(asList(1L, 2L)) .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()) .setDiscountPercent(50).setDiscountLimitPrice(70)); when(couponApi.validateCoupon(eq(new CouponValidReqDTO().setId(1024L).setUserId(233L)))).thenReturn(coupon); From 71efa0ed6f7c684f11f74606ddd0268cfe6c2b0e Mon Sep 17 00:00:00 2001 From: owen Date: Sat, 2 Sep 2023 10:05:56 +0800 Subject: [PATCH 14/15] =?UTF-8?q?promotion:=20=E8=AE=A2=E5=8D=95=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=93=81=E7=B1=BB=E5=88=B8=E6=97=B6=EF=BC=8C=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=E5=93=81=E7=B1=BB=E8=BF=87=E6=BB=A4=E5=8F=AF=E7=94=A8?= =?UTF-8?q?=E5=95=86=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/price/calculator/TradeCouponPriceCalculator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java index 96db8175c..68955ce51 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java @@ -103,6 +103,9 @@ public class TradeCouponPriceCalculator implements TradePriceCalculator { if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) { matchPredicate = matchPredicate // 额外加如下条件 .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getSpuId())); + } else if (PromotionProductScopeEnum.CATEGORY.getScope().equals(coupon.getProductScope())) { + matchPredicate = matchPredicate // 额外加如下条件 + .and(orderItem -> coupon.getProductScopeValues().contains(orderItem.getCategoryId())); } return filterList(result.getItems(), matchPredicate); } From 482a84a6f1059fa4726892c0fcbd249c73ba2d1d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 3 Sep 2023 18:06:15 +0800 Subject: [PATCH 15/15] =?UTF-8?q?603=20mall:=20=E4=BC=98=E6=83=A0=E5=88=B8?= =?UTF-8?q?=E9=80=80=E8=BF=98=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/coupon/vo/template/CouponTemplateBaseVO.java | 2 +- .../module/promotion/service/coupon/CouponServiceImpl.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java index dff0d8d78..2529f79ac 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java @@ -54,7 +54,7 @@ public class CouponTemplateBaseVO { @InEnum(PromotionProductScopeEnum.class) private Integer productScope; - @Schema(description = "商品范围编号的数组", example = "1,3") + @Schema(description = "商品范围编号的数组", example = "[1, 3]") private List productScopeValues; @Schema(description = "生效日期类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 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 4192126ad..f4b56260c 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 @@ -93,6 +93,7 @@ public class CouponServiceImpl implements CouponService { public void useCoupon(Long id, Long userId, Long orderId) { // 校验优惠劵 validCoupon(id, userId); + // 更新状态 int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(), new CouponDO().setStatus(CouponStatusEnum.USED.getStatus()) @@ -116,10 +117,10 @@ public class CouponServiceImpl implements CouponService { // 退还 Integer status = LocalDateTimeUtils.beforeNow(coupon.getValidEndTime()) - // 退还时可能已经过期了 - ? CouponStatusEnum.EXPIRE.getStatus() + ? CouponStatusEnum.EXPIRE.getStatus() // 退还时可能已经过期了 : CouponStatusEnum.UNUSED.getStatus(); - int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(), new CouponDO().setStatus(status)); + int updateCount = couponMapper.updateByIdAndStatus(id, CouponStatusEnum.UNUSED.getStatus(), + new CouponDO().setStatus(status)); if (updateCount == 0) { throw exception(COUPON_STATUS_NOT_USED); }