Commit fb45f2253339f4e844801fc7bbcf3774c1e24c60

Authored by LAPTOP-CNV4CMCJ\cheng
2 parents ea5e6b2c 05614cc0

Merge branch 'feature/1.8.0-uniapp' of https://gitee.com/zhijiantianya/ruoyi-vue…

…-pro into feature/1.8.0-uniapp
Showing 110 changed files with 4078 additions and 1007 deletions
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java
1 package cn.iocoder.yudao.module.product.controller.admin.sku; 1 package cn.iocoder.yudao.module.product.controller.admin.sku;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  6 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO;
  7 +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
  8 +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
  9 +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
  10 +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
  11 +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
3 import io.swagger.annotations.Api; 12 import io.swagger.annotations.Api;
  13 +import io.swagger.annotations.ApiOperation;
4 import org.springframework.validation.annotation.Validated; 14 import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.GetMapping;
5 import org.springframework.web.bind.annotation.RequestMapping; 16 import org.springframework.web.bind.annotation.RequestMapping;
6 import org.springframework.web.bind.annotation.RestController; 17 import org.springframework.web.bind.annotation.RestController;
7 18
  19 +import javax.annotation.Resource;
  20 +import java.util.Collections;
  21 +import java.util.List;
  22 +import java.util.Map;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  25 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  26 +
8 @Api(tags = "管理后台 - 商品 sku") 27 @Api(tags = "管理后台 - 商品 sku")
9 @RestController 28 @RestController
10 @RequestMapping("/product/sku") 29 @RequestMapping("/product/sku")
11 @Validated 30 @Validated
12 public class ProductSkuController { 31 public class ProductSkuController {
13 32
  33 + @Resource
  34 + private ProductSkuService productSkuService;
  35 + @Resource
  36 + private ProductSpuService productSpuService;
  37 +
  38 + @GetMapping("/get-option-list")
  39 + @ApiOperation("获得商品 SKU 选项的列表")
  40 +// @PreAuthorize("@ss.hasPermission('product:sku:query')")
  41 + public CommonResult<List<ProductSkuOptionRespVO>> getSkuOptionList() {
  42 + // 获得 SKU 列表
  43 + List<ProductSkuDO> skus = productSkuService.getSkuList();
  44 + if (CollUtil.isEmpty(skus)) {
  45 + return success(Collections.emptyList());
  46 + }
  47 +
  48 + // 获得对应的 SPU 映射
  49 + Map<Long, ProductSpuDO> spuMap = productSpuService.getSpuMap(convertSet(skus, ProductSkuDO::getSpuId));
  50 + // 转换为返回结果
  51 + List<ProductSkuOptionRespVO> skuVOs = ProductSkuConvert.INSTANCE.convertList05(skus);
  52 + skuVOs.forEach(sku -> MapUtils.findAndThen(spuMap, sku.getSpuId(),
  53 + spu -> sku.setSpuId(spu.getId()).setSpuName(spu.getName())));
  54 + return success(skuVOs);
  55 + }
  56 +
14 } 57 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.product.controller.admin.sku.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +
  7 +@ApiModel(value = "管理后台 - 商品 SKU 选项 Response VO", description = "用于前端 SELECT 选项")
  8 +@Data
  9 +public class ProductSkuOptionRespVO {
  10 +
  11 + @ApiModelProperty(value = "主键", required = true, example = "1024")
  12 + private Long id;
  13 +
  14 + @ApiModelProperty(value = "商品 SKU 名字", example = "红色")
  15 + private String name;
  16 +
  17 + @ApiModelProperty(value = "销售价格", required = true, example = "100", notes = "单位:分")
  18 + private String price;
  19 +
  20 + @ApiModelProperty(value = "库存", required = true, example = "100")
  21 + private Integer stock;
  22 +
  23 + // ========== 商品 SPU 信息 ==========
  24 +
  25 + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1")
  26 + private Long spuId;
  27 +
  28 + @ApiModelProperty(value = "商品 SPU 名字", required = true, example = "iPhone 11")
  29 + private String spuName;
  30 +
  31 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java
@@ -9,7 +9,7 @@ import lombok.ToString; @@ -9,7 +9,7 @@ import lombok.ToString;
9 import java.util.Date; 9 import java.util.Date;
10 import java.util.List; 10 import java.util.List;
11 11
12 -@ApiModel("管理后台 - 商品sku Response VO") 12 +@ApiModel("管理后台 - 商品 SKU Response VO")
13 @Data 13 @Data
14 @EqualsAndHashCode(callSuper = true) 14 @EqualsAndHashCode(callSuper = true)
15 @ToString(callSuper = true) 15 @ToString(callSuper = true)
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java
@@ -53,6 +53,7 @@ public class ProductSpuController { @@ -53,6 +53,7 @@ public class ProductSpuController {
53 return success(true); 53 return success(true);
54 } 54 }
55 55
  56 + // TODO 芋艿:修改接口
56 @GetMapping("/get/detail") 57 @GetMapping("/get/detail")
57 @ApiOperation("获得商品 SPU") 58 @ApiOperation("获得商品 SPU")
58 @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) 59 @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@@ -79,6 +80,14 @@ public class ProductSpuController { @@ -79,6 +80,14 @@ public class ProductSpuController {
79 return success(ProductSpuConvert.INSTANCE.convertList(list)); 80 return success(ProductSpuConvert.INSTANCE.convertList(list));
80 } 81 }
81 82
  83 + @GetMapping("/get-simple-list")
  84 + @ApiOperation("获得商品 SPU 精简列表")
  85 + @PreAuthorize("@ss.hasPermission('product:spu:query')")
  86 + public CommonResult<List<ProductSpuSimpleRespVO>> getSpuSimpleList() {
  87 + List<ProductSpuDO> list = spuService.getSpuList();
  88 + return success(ProductSpuConvert.INSTANCE.convertList02(list));
  89 + }
  90 +
82 @GetMapping("/page") 91 @GetMapping("/page")
83 @ApiOperation("获得商品 SPU 分页") 92 @ApiOperation("获得商品 SPU 分页")
84 @PreAuthorize("@ss.hasPermission('product:spu:query')") 93 @PreAuthorize("@ss.hasPermission('product:spu:query')")
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +@ApiModel("管理后台 - 商品 SPU 精简 Response VO")
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = true)
  12 +@ToString(callSuper = true)
  13 +public class ProductSpuSimpleRespVO extends ProductSpuBaseVO {
  14 +
  15 + @ApiModelProperty(value = "主键", required = true, example = "1")
  16 + private Long id;
  17 +
  18 + @ApiModelProperty(value = "商品名称", required = true, example = "芋道")
  19 + private String name;
  20 +
  21 + @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024")
  22 + private Integer minPrice;
  23 +
  24 + @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024")
  25 + private Integer maxPrice;
  26 +
  27 +}
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.convert.sku; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.product.convert.sku;
2 2
3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 3 import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; 4 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
  5 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO;
5 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; 6 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO;
6 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO; 7 import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO;
7 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; 8 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
@@ -11,7 +12,7 @@ import org.mapstruct.factory.Mappers; @@ -11,7 +12,7 @@ import org.mapstruct.factory.Mappers;
11 import java.util.List; 12 import java.util.List;
12 13
13 /** 14 /**
14 - * 商品sku Convert 15 + * 商品 SKU Convert
15 * 16 *
16 * @author 芋道源码 17 * @author 芋道源码
17 */ 18 */
@@ -36,4 +37,6 @@ public interface ProductSkuConvert { @@ -36,4 +37,6 @@ public interface ProductSkuConvert {
36 37
37 List<ProductSkuRespDTO> convertList04(List<ProductSkuDO> list); 38 List<ProductSkuRespDTO> convertList04(List<ProductSkuDO> list);
38 39
  40 + List<ProductSkuOptionRespVO> convertList05(List<ProductSkuDO> skus);
  41 +
39 } 42 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
@@ -36,5 +36,7 @@ public interface ProductSpuConvert { @@ -36,5 +36,7 @@ public interface ProductSpuConvert {
36 AppSpuPageRespVO convertAppResp(ProductSpuDO list); 36 AppSpuPageRespVO convertAppResp(ProductSpuDO list);
37 37
38 List<SpuInfoRespDTO> convertList2(List<ProductSpuDO> list); 38 List<SpuInfoRespDTO> convertList2(List<ProductSpuDO> list);
39 - 39 +
  40 + List<ProductSpuSimpleRespVO> convertList02(List<ProductSpuDO> list);
  41 +
40 } 42 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java
@@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO { @@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO {
97 * 商品属性 97 * 商品属性
98 */ 98 */
99 @Data 99 @Data
  100 + @NoArgsConstructor
100 @AllArgsConstructor 101 @AllArgsConstructor
101 public static class Property { 102 public static class Property {
102 103
@@ -130,19 +131,5 @@ public class ProductSkuDO extends BaseDO { @@ -130,19 +131,5 @@ public class ProductSkuDO extends BaseDO {
130 131
131 } 132 }
132 133
133 - // TODO ========== 待定字段:yv =========  
134 - // TODO brokerage:一级返佣  
135 - // TODO brokerage_two:二级返佣  
136 - // TODO pink_price:拼团价  
137 - // TODO pink_stock:拼团库存  
138 - // TODO seckill_price:秒杀价  
139 - // TODO seckill_stock:秒杀库存  
140 - // TODO integral:需要积分  
141 -  
142 - // TODO ========== 待定字段:cf =========  
143 - // TODO type 活动显示排序 0=默认 1=秒 2=砍价 3=拼团  
144 - // TODO quota 活动限购数量  
145 - // TODO quota_show 活动限购数量显示  
146 -  
147 } 134 }
148 135
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java
@@ -14,22 +14,29 @@ import java.util.List; @@ -14,22 +14,29 @@ import java.util.List;
14 public interface ProductSkuService { 14 public interface ProductSkuService {
15 15
16 /** 16 /**
17 - * 删除商品sku 17 + * 删除商品 SKU
18 * 18 *
19 * @param id 编号 19 * @param id 编号
20 */ 20 */
21 void deleteSku(Long id); 21 void deleteSku(Long id);
22 22
23 /** 23 /**
24 - * 获得商品sku 24 + * 获得商品 SKU 信息
25 * 25 *
26 * @param id 编号 26 * @param id 编号
27 - * @return 商品sku 27 + * @return 商品 SKU 信息
28 */ 28 */
29 ProductSkuDO getSku(Long id); 29 ProductSkuDO getSku(Long id);
30 30
31 /** 31 /**
32 - * 获得商品sku列表 32 + * 获得商品 SKU 列表
  33 + *
  34 + * @return 商品sku列表
  35 + */
  36 + List<ProductSkuDO> getSkuList();
  37 +
  38 + /**
  39 + * 获得商品 SKU 列表
33 * 40 *
34 * @param ids 编号 41 * @param ids 编号
35 * @return 商品sku列表 42 * @return 商品sku列表
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
@@ -62,6 +62,11 @@ public class ProductSkuServiceImpl implements ProductSkuService { @@ -62,6 +62,11 @@ public class ProductSkuServiceImpl implements ProductSkuService {
62 } 62 }
63 63
64 @Override 64 @Override
  65 + public List<ProductSkuDO> getSkuList() {
  66 + return productSkuMapper.selectList();
  67 + }
  68 +
  69 + @Override
65 public List<ProductSkuDO> getSkuList(Collection<Long> ids) { 70 public List<ProductSkuDO> getSkuList(Collection<Long> ids) {
66 return productSkuMapper.selectBatchIds(ids); 71 return productSkuMapper.selectBatchIds(ids);
67 } 72 }
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java
@@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; @@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
9 import javax.validation.Valid; 9 import javax.validation.Valid;
10 import java.util.Collection; 10 import java.util.Collection;
11 import java.util.List; 11 import java.util.List;
  12 +import java.util.Map;
  13 +
  14 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
12 15
13 /** 16 /**
14 * 商品 SPU Service 接口 17 * 商品 SPU Service 接口
@@ -64,6 +67,23 @@ public interface ProductSpuService { @@ -64,6 +67,23 @@ public interface ProductSpuService {
64 List<ProductSpuDO> getSpuList(Collection<Long> ids); 67 List<ProductSpuDO> getSpuList(Collection<Long> ids);
65 68
66 /** 69 /**
  70 + * 获得商品 SPU 映射
  71 + *
  72 + * @param ids 编号数组
  73 + * @return 商品 SPU 映射
  74 + */
  75 + default Map<Long, ProductSpuDO> getSpuMap(Collection<Long> ids) {
  76 + return convertMap(getSpuList(ids), ProductSpuDO::getId);
  77 + }
  78 +
  79 + /**
  80 + * 获得所有商品 SPU 列表
  81 + *
  82 + * @return 商品 SPU 列表
  83 + */
  84 + List<ProductSpuDO> getSpuList();
  85 +
  86 + /**
67 * 获得商品 SPU 分页 87 * 获得商品 SPU 分页
68 * 88 *
69 * @param pageReqVO 分页查询 89 * @param pageReqVO 分页查询
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
@@ -177,6 +177,11 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -177,6 +177,11 @@ public class ProductSpuServiceImpl implements ProductSpuService {
177 } 177 }
178 178
179 @Override 179 @Override
  180 + public List<ProductSpuDO> getSpuList() {
  181 + return productSpuMapper.selectList();
  182 + }
  183 +
  184 + @Override
180 public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) { 185 public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
181 // 库存告警的 SPU 编号的集合 186 // 库存告警的 SPU 编号的集合
182 Set<Long> alarmStockSpuIds = null; 187 Set<Long> alarmStockSpuIds = null;
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java
@@ -48,10 +48,18 @@ public class PriceCalculateRespDTO { @@ -48,10 +48,18 @@ public class PriceCalculateRespDTO {
48 * 商品原价(总),单位:分 48 * 商品原价(总),单位:分
49 * 49 *
50 * 基于 {@link OrderItem#getOriginalPrice()} 求和 50 * 基于 {@link OrderItem#getOriginalPrice()} 求和
  51 + *
51 * 对应 taobao 的 trade.total_fee 字段 52 * 对应 taobao 的 trade.total_fee 字段
52 */ 53 */
53 private Integer originalPrice; 54 private Integer originalPrice;
54 /** 55 /**
  56 + * 订单原价(总),单位:分
  57 + *
  58 + * 基于 {@link OrderItem#getPayPrice()} 求和
  59 + * 和 {@link #originalPrice} 的差异:去除商品级优惠
  60 + */
  61 + private Integer orderPrice;
  62 + /**
55 * 订单优惠(总),单位:分 63 * 订单优惠(总),单位:分
56 * 64 *
57 * 订单级优惠:对主订单的优惠,常见如:订单满 200 元减 10 元;订单满 80 包邮。 65 * 订单级优惠:对主订单的优惠,常见如:订单满 200 元减 10 元;订单满 80 包邮。
@@ -82,6 +90,7 @@ public class PriceCalculateRespDTO { @@ -82,6 +90,7 @@ public class PriceCalculateRespDTO {
82 * - {@link #couponPrice} 90 * - {@link #couponPrice}
83 * - {@link #pointPrice} 91 * - {@link #pointPrice}
84 * + {@link #deliveryPrice} 92 * + {@link #deliveryPrice}
  93 + * - {@link #discountPrice}
85 */ 94 */
86 private Integer payPrice; 95 private Integer payPrice;
87 /** 96 /**
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
@@ -3,14 +3,19 @@ package cn.iocoder.yudao.module.promotion.enums; @@ -3,14 +3,19 @@ package cn.iocoder.yudao.module.promotion.enums;
3 import cn.iocoder.yudao.framework.common.exception.ErrorCode; 3 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 4
5 /** 5 /**
6 - * market 错误码枚举类  
7 - * <p> 6 + * promotion 错误码枚举类
  7 + *
8 * market 系统,使用 1-003-000-000 段 8 * market 系统,使用 1-003-000-000 段
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
11 11
12 - // ========== 促销活动相关 1003001000 ============ TODO 芋艿:看看是不是要删除掉  
13 - ErrorCode ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "促销活动不存在"); 12 + // ========== 促销活动相关 1003001000 ============
  13 + ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "限时折扣活动不存在");
  14 + ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003006001, "存在商品参加了其它限时折扣活动");
  15 + ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1003006002, "限时折扣活动已关闭,不能修改");
  16 + ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1003006003, "限时折扣活动未关闭,不能删除");
  17 + ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1003006004, "限时折扣活动已关闭,不能重复关闭");
  18 + ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1003006004, "限时折扣活动已结束,不能关闭");
14 19
15 // ========== Banner 相关 1003002000 ============ 20 // ========== Banner 相关 1003002000 ============
16 ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1003002000, "Banner 不存在"); 21 ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1003002000, "Banner 不存在");
@@ -23,4 +28,19 @@ public interface ErrorCodeConstants { @@ -23,4 +28,19 @@ public interface ErrorCodeConstants {
23 ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1003004000, "优惠劵模板不存在"); 28 ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1003004000, "优惠劵模板不存在");
24 ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1003004001, "发放数量不能小于已领取数量({})"); 29 ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1003004001, "发放数量不能小于已领取数量({})");
25 30
  31 + // ========== 优惠劵模板 1003005000 ==========
  32 + ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1003005000, "优惠劵不存在");
  33 + ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1003005001, "回收优惠劵失败,优惠劵已被使用");
  34 +
  35 + // ========== 满减送活动 1003006000 ==========
  36 + ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1003006000, "满减送活动不存在");
  37 + ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003006001, "存在商品参加了其它满减送活动");
  38 + ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1003006002, "满减送活动已关闭,不能修改");
  39 + ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1003006003, "满减送活动未关闭,不能删除");
  40 + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1003006004, "满减送活动已关闭,不能重复关闭");
  41 + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1003006004, "满减送活动已结束,不能关闭");
  42 +
  43 + // ========== Price 相关 1003007000 ============
  44 + ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1003007000, "支付价格计算异常,原因:价格小于等于 0");
  45 +
26 } 46 }
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.enums.coupon;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * 优惠劵状态枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum CouponStatusEnum implements IntArrayValuable {
  17 +
  18 + UNUSED(1, "未使用"),
  19 + USED(2, "已使用"),
  20 + EXPIRE(3, "已过期"),
  21 + ;
  22 +
  23 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray();
  24 +
  25 + /**
  26 + * 值
  27 + */
  28 + private final Integer status;
  29 + /**
  30 + * 名字
  31 + */
  32 + private final String name;
  33 +
  34 + @Override
  35 + public int[] array() {
  36 + return ARRAYS;
  37 + }
  38 +
  39 +}
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java
1 package cn.iocoder.yudao.module.promotion.enums.coupon; 1 package cn.iocoder.yudao.module.promotion.enums.coupon;
2 2
3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable; 3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
4 6
5 import java.util.Arrays; 7 import java.util.Arrays;
6 8
@@ -9,6 +11,8 @@ import java.util.Arrays; @@ -9,6 +11,8 @@ import java.util.Arrays;
9 * 11 *
10 * @author 芋道源码 12 * @author 芋道源码
11 */ 13 */
  14 +@AllArgsConstructor
  15 +@Getter
12 public enum CouponTakeTypeEnum implements IntArrayValuable { 16 public enum CouponTakeTypeEnum implements IntArrayValuable {
13 17
14 BY_USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 18 BY_USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取
@@ -26,19 +30,6 @@ public enum CouponTakeTypeEnum implements IntArrayValuable { @@ -26,19 +30,6 @@ public enum CouponTakeTypeEnum implements IntArrayValuable {
26 */ 30 */
27 private final String name; 31 private final String name;
28 32
29 - CouponTakeTypeEnum(Integer value, String name) {  
30 - this.value = value;  
31 - this.name = name;  
32 - }  
33 -  
34 - public Integer getValue() {  
35 - return value;  
36 - }  
37 -  
38 - public String getName() {  
39 - return name;  
40 - }  
41 -  
42 @Override 33 @Override
43 public int[] array() { 34 public int[] array() {
44 return ARRAYS; 35 return ARRAYS;
yudao-module-mall/yudao-module-promotion-biz/pom.xml
@@ -29,6 +29,11 @@ @@ -29,6 +29,11 @@
29 <artifactId>yudao-module-product-api</artifactId> 29 <artifactId>yudao-module-product-api</artifactId>
30 <version>${revision}</version> 30 <version>${revision}</version>
31 </dependency> 31 </dependency>
  32 + <dependency>
  33 + <groupId>cn.iocoder.boot</groupId>
  34 + <artifactId>yudao-module-member-api</artifactId>
  35 + <version>${revision}</version>
  36 + </dependency>
32 37
33 <!-- 业务组件 --> 38 <!-- 业务组件 -->
34 <dependency> 39 <dependency>
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  7 +import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
  8 +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
  9 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO;
  10 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
  11 +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
  12 +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
  13 +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
  14 +import io.swagger.annotations.Api;
  15 +import io.swagger.annotations.ApiImplicitParam;
  16 +import io.swagger.annotations.ApiOperation;
  17 +import org.springframework.security.access.prepost.PreAuthorize;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import javax.annotation.Resource;
  22 +import javax.validation.Valid;
  23 +import java.util.Map;
  24 +import java.util.Set;
  25 +
  26 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  28 +
  29 +@Api(tags = "管理后台 - 优惠劵")
  30 +@RestController
  31 +@RequestMapping("/promotion/coupon")
  32 +@Validated
  33 +public class CouponController {
  34 +
  35 + @Resource
  36 + private CouponService couponService;
  37 + @Resource
  38 + private MemberUserApi memberUserApi;
  39 +
  40 +// @GetMapping("/get")
  41 +// @ApiOperation("获得优惠劵")
  42 +// @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  43 +// @PreAuthorize("@ss.hasPermission('promotion:coupon:query')")
  44 +// public CommonResult<CouponRespVO> getCoupon(@RequestParam("id") Long id) {
  45 +// CouponDO coupon = couponService.getCoupon(id);
  46 +// return success(CouponConvert.INSTANCE.convert(coupon));
  47 +// }
  48 +
  49 + @DeleteMapping("/delete")
  50 + @ApiOperation("回收优惠劵")
  51 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  52 + @PreAuthorize("@ss.hasPermission('promotion:coupon:delete')")
  53 + public CommonResult<Boolean> deleteCoupon(@RequestParam("id") Long id) {
  54 + couponService.deleteCoupon(id);
  55 + return success(true);
  56 + }
  57 +
  58 + @GetMapping("/page")
  59 + @ApiOperation("获得优惠劵分页")
  60 + @PreAuthorize("@ss.hasPermission('promotion:coupon:query')")
  61 + public CommonResult<PageResult<CouponPageItemRespVO>> getCouponPage(@Valid CouponPageReqVO pageVO) {
  62 + PageResult<CouponDO> pageResult = couponService.getCouponPage(pageVO);
  63 + PageResult<CouponPageItemRespVO> pageResulVO = CouponConvert.INSTANCE.convertPage(pageResult);
  64 + if (CollUtil.isEmpty(pageResulVO.getList())) {
  65 + return success(pageResulVO);
  66 + }
  67 + // 读取用户信息,进行拼接
  68 + Set<Long> userIds = convertSet(pageResult.getList(), CouponDO::getUserId);
  69 + Map<Long, UserRespDTO> userMap = memberUserApi.getUserMap(userIds);
  70 + pageResulVO.getList().forEach(itemRespVO -> MapUtils.findAndThen(userMap, itemRespVO.getUserId(),
  71 + userRespDTO -> itemRespVO.setNickname(userRespDTO.getNickname())));
  72 + return success(pageResulVO);
  73 + }
  74 +
  75 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java
@@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon; @@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO;  
7 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateRespVO;  
8 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 5 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.*;
9 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; 6 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert;
10 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
11 import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; 8 import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService;
@@ -45,6 +42,14 @@ public class CouponTemplateController { @@ -45,6 +42,14 @@ public class CouponTemplateController {
45 return success(true); 42 return success(true);
46 } 43 }
47 44
  45 + @PutMapping("/update-status")
  46 + @ApiOperation("更新优惠劵模板状态")
  47 + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:update')")
  48 + public CommonResult<Boolean> updateCouponTemplateStatus(@Valid @RequestBody CouponTemplateUpdateStatusReqVO reqVO) {
  49 + couponTemplateService.updateCouponTemplateStatus(reqVO.getId(), reqVO.getStatus());
  50 + return success(true);
  51 + }
  52 +
48 @DeleteMapping("/delete") 53 @DeleteMapping("/delete")
49 @ApiOperation("删除优惠劵模板") 54 @ApiOperation("删除优惠劵模板")
50 @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) 55 @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
  5 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonFormat;
  7 +import io.swagger.annotations.ApiModelProperty;
  8 +import lombok.Data;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import javax.validation.constraints.Min;
  12 +import javax.validation.constraints.NotNull;
  13 +import java.util.Date;
  14 +import java.util.List;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  17 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
  18 +
  19 +/**
  20 +* 优惠劵 Base VO,提供给添加、修改、详细的子 VO 使用
  21 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  22 +*/
  23 +@Data
  24 +public class CouponBaseVO {
  25 +
  26 + // ========== 基本信息 BEGIN ==========
  27 + @ApiModelProperty(value = "优惠劵模板编号", required = true, example = "1024")
  28 + @NotNull(message = "优惠劵模板编号不能为空")
  29 + private Integer templateId;
  30 +
  31 + @ApiModelProperty(value = "优惠劵名", required = true, example = "春节送送送")
  32 + @NotNull(message = "优惠劵名不能为空")
  33 + private String name;
  34 +
  35 + @ApiModelProperty(value = "优惠码状态", required = true, example = "1", notes = "参见 CouponStatusEnum 枚举")
  36 + private Integer status;
  37 +
  38 + // ========== 基本信息 END ==========
  39 +
  40 + // ========== 领取情况 BEGIN ==========
  41 + @ApiModelProperty(value = "用户编号", required = true, example = "1")
  42 + @NotNull(message = "用户编号不能为空")
  43 + private Long userId;
  44 +
  45 + @ApiModelProperty(value = "领取方式", required = true, example = "1", notes = "参见 CouponTakeTypeEnum 枚举类")
  46 + @NotNull(message = "领取方式不能为空")
  47 + private Integer takeType;
  48 + // ========== 领取情况 END ==========
  49 +
  50 + // ========== 使用规则 BEGIN ==========
  51 + @ApiModelProperty(value = "是否设置满多少金额可用", required = true, example = "100", notes = "单位:分;0 - 不限制")
  52 + @NotNull(message = "是否设置满多少金额可用不能为空")
  53 + private Integer usePrice;
  54 +
  55 + @ApiModelProperty(value = "固定日期 - 生效开始时间")
  56 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  57 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  58 + private Date validStartTime;
  59 +
  60 + @ApiModelProperty(value = "固定日期 - 生效结束时间")
  61 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  62 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  63 + private Date validEndTime;
  64 +
  65 + @ApiModelProperty(value = "商品范围", required = true, example = "1", notes = "参见 PromotionProductScopeEnum 枚举类")
  66 + @NotNull(message = "商品范围不能为空")
  67 + @InEnum(PromotionProductScopeEnum.class)
  68 + private Integer productScope;
  69 +
  70 + @ApiModelProperty(value = "商品 SPU 编号的数组", example = "1,3")
  71 + private List<Long> productSpuIds;
  72 + // ========== 使用规则 END ==========
  73 +
  74 + // ========== 使用效果 BEGIN ==========
  75 + @ApiModelProperty(value = "优惠类型", required = true, example = "1", notes = "参见 PromotionDiscountTypeEnum 枚举")
  76 + @NotNull(message = "优惠类型不能为空")
  77 + @InEnum(PromotionDiscountTypeEnum.class)
  78 + private Integer discountType;
  79 +
  80 + @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80")
  81 + private Integer discountPercent;
  82 +
  83 + @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分")
  84 + @Min(value = 0, message = "优惠金额需要大于等于 0")
  85 + private Integer discountPrice;
  86 +
  87 + @ApiModelProperty(value = "折扣上限", example = "100", notes = "单位:分,仅在 discountType 为 PERCENT 使用")
  88 + private Integer discountLimitPrice;
  89 + // ========== 使用效果 END ==========
  90 +
  91 + // ========== 使用情况 BEGIN ==========
  92 +
  93 + @ApiModelProperty(value = "使用订单号", example = "4096")
  94 + private Long useOrderId;
  95 +
  96 + @ApiModelProperty(value = "使用时间")
  97 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  98 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
  99 + private Date useTime;
  100 +
  101 + // ========== 使用情况 END ==========
  102 +
  103 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageItemRespVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +@ApiModel("管理后台 - 优惠劵分页的每一项 Response VO")
  10 +@Data
  11 +@EqualsAndHashCode(callSuper = true)
  12 +@ToString(callSuper = true)
  13 +public class CouponPageItemRespVO extends CouponRespVO {
  14 +
  15 + @ApiModelProperty(value = "用户昵称", example = "老芋艿")
  16 + private String nickname;
  17 +
  18 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("管理后台 - 优惠劵分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class CouponPageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "优惠劵模板编号", example = "2048")
  22 + private Long templateId;
  23 +
  24 + @ApiModelProperty(value = "优惠码状态", example = "1", notes = "参见 CouponStatusEnum 枚举")
  25 + private Integer status;
  26 +
  27 + @ApiModelProperty(value = "创建时间")
  28 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  29 + private Date[] createTime;
  30 +
  31 + @ApiModelProperty(value = "用户昵称", example = "芋艿", notes = "模糊匹配")
  32 + private String nickname;
  33 +
  34 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponRespVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.util.Date;
  10 +
  11 +@ApiModel("管理后台 - 优惠劵 Response VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class CouponRespVO extends CouponBaseVO {
  16 +
  17 + @ApiModelProperty(value = "优惠劵编号", required = true, example = "1024")
  18 + private Long id;
  19 +
  20 + @ApiModelProperty(value = "创建时间", required = true)
  21 + private Date createTime;
  22 +
  23 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateBaseVO.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java
1 -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; 1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.ObjectUtil; 4 import cn.hutool.core.util.ObjectUtil;
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum;
6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; 6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
7 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; 7 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
8 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; 8 import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
  9 +import com.fasterxml.jackson.annotation.JsonFormat;
9 import com.fasterxml.jackson.annotation.JsonIgnore; 10 import com.fasterxml.jackson.annotation.JsonIgnore;
10 import io.swagger.annotations.ApiModelProperty; 11 import io.swagger.annotations.ApiModelProperty;
11 import lombok.Data; 12 import lombok.Data;
@@ -19,6 +20,7 @@ import java.util.List; @@ -19,6 +20,7 @@ import java.util.List;
19 import java.util.Objects; 20 import java.util.Objects;
20 21
21 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; 22 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  23 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
22 24
23 /** 25 /**
24 * 优惠劵模板 Base VO,提供给添加、修改、详细的子 VO 使用 26 * 优惠劵模板 Base VO,提供给添加、修改、详细的子 VO 使用
@@ -62,10 +64,12 @@ public class CouponTemplateBaseVO { @@ -62,10 +64,12 @@ public class CouponTemplateBaseVO {
62 64
63 @ApiModelProperty(value = "固定日期 - 生效开始时间") 65 @ApiModelProperty(value = "固定日期 - 生效开始时间")
64 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 66 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  67 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
65 private Date validStartTime; 68 private Date validStartTime;
66 69
67 @ApiModelProperty(value = "固定日期 - 生效结束时间") 70 @ApiModelProperty(value = "固定日期 - 生效结束时间")
68 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 71 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  72 + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT)
69 private Date validEndTime; 73 private Date validEndTime;
70 74
71 @ApiModelProperty(value = "领取日期 - 开始天数") 75 @ApiModelProperty(value = "领取日期 - 开始天数")
@@ -82,15 +86,14 @@ public class CouponTemplateBaseVO { @@ -82,15 +86,14 @@ public class CouponTemplateBaseVO {
82 private Integer discountType; 86 private Integer discountType;
83 87
84 @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80") 88 @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80")
85 - @Min(value = 1)  
86 private Integer discountPercent; 89 private Integer discountPercent;
87 90
88 @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分") 91 @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分")
89 - @Min(value = 1) 92 + @Min(value = 0, message = "优惠金额需要大于等于 0")
90 private Integer discountPrice; 93 private Integer discountPrice;
91 94
92 @ApiModelProperty(value = "折扣上限", example = "100", notes = "单位:分,仅在 discountType 为 PERCENT 使用") 95 @ApiModelProperty(value = "折扣上限", example = "100", notes = "单位:分,仅在 discountType 为 PERCENT 使用")
93 - private Integer discountPriceLimit; 96 + private Integer discountLimitPrice;
94 97
95 @AssertTrue(message = "商品 SPU 编号的数组不能为空") 98 @AssertTrue(message = "商品 SPU 编号的数组不能为空")
96 @JsonIgnore 99 @JsonIgnore
@@ -127,11 +130,11 @@ public class CouponTemplateBaseVO { @@ -127,11 +130,11 @@ public class CouponTemplateBaseVO {
127 || fixedEndTerm != null; 130 || fixedEndTerm != null;
128 } 131 }
129 132
130 - @AssertTrue(message = "折扣百分比不能为空") 133 + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99")
131 @JsonIgnore 134 @JsonIgnore
132 public boolean isDiscountPercentValid() { 135 public boolean isDiscountPercentValid() {
133 return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) 136 return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
134 - || discountPercent != null; 137 + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99);
135 } 138 }
136 139
137 @AssertTrue(message = "优惠金额不能为空") 140 @AssertTrue(message = "优惠金额不能为空")
@@ -143,9 +146,9 @@ public class CouponTemplateBaseVO { @@ -143,9 +146,9 @@ public class CouponTemplateBaseVO {
143 146
144 @AssertTrue(message = "折扣上限不能为空") 147 @AssertTrue(message = "折扣上限不能为空")
145 @JsonIgnore 148 @JsonIgnore
146 - public boolean isDiscountPriceLimit() { 149 + public boolean isDiscountLimitPriceValid() {
147 return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) 150 return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
148 - || discountPriceLimit != null; 151 + || discountLimitPrice != null;
149 } 152 }
150 153
151 } 154 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateCreateReqVO.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateCreateReqVO.java
1 -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; 1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template;
2 2
3 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
4 import lombok.Data; 4 import lombok.Data;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplatePageReqVO.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java
1 -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; 1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import cn.iocoder.yudao.framework.common.validation.InEnum; 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateRespVO.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateRespVO.java
1 -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; 1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template;
2 2
3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import cn.iocoder.yudao.framework.common.validation.InEnum; 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateUpdateReqVO.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateReqVO.java
1 -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; 1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template;
2 2
3 import io.swagger.annotations.ApiModel; 3 import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 4 import io.swagger.annotations.ApiModelProperty;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateStatusReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import io.swagger.annotations.ApiModel;
  6 +import io.swagger.annotations.ApiModelProperty;
  7 +import lombok.Data;
  8 +
  9 +import javax.validation.constraints.NotNull;
  10 +
  11 +@ApiModel("管理后台 - 优惠劵模板更新状态 Request VO")
  12 +@Data
  13 +public class CouponTemplateUpdateStatusReqVO {
  14 +
  15 + @ApiModelProperty(value = "优惠劵模板编号", required = true, example = "1024")
  16 + @NotNull(message = "优惠劵模板编号不能为空")
  17 + private Long id;
  18 +
  19 + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举")
  20 + @NotNull(message = "状态不能为空")
  21 + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
  22 + private Integer status;
  23 +
  24 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.discount;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
  6 +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  9 +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
  10 +import io.swagger.annotations.Api;
  11 +import io.swagger.annotations.ApiImplicitParam;
  12 +import io.swagger.annotations.ApiOperation;
  13 +import org.springframework.security.access.prepost.PreAuthorize;
  14 +import org.springframework.validation.annotation.Validated;
  15 +import org.springframework.web.bind.annotation.*;
  16 +
  17 +import javax.annotation.Resource;
  18 +import javax.validation.Valid;
  19 +import java.util.List;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +@Api(tags = "管理后台 - 限时折扣活动")
  24 +@RestController
  25 +@RequestMapping("/promotion/discount-activity")
  26 +@Validated
  27 +public class DiscountActivityController {
  28 +
  29 + @Resource
  30 + private DiscountActivityService discountActivityService;
  31 +
  32 + @PostMapping("/create")
  33 + @ApiOperation("创建限时折扣活动")
  34 + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')")
  35 + public CommonResult<Long> createDiscountActivity(@Valid @RequestBody DiscountActivityCreateReqVO createReqVO) {
  36 + return success(discountActivityService.createDiscountActivity(createReqVO));
  37 + }
  38 +
  39 + @PutMapping("/update")
  40 + @ApiOperation("更新限时折扣活动")
  41 + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:update')")
  42 + public CommonResult<Boolean> updateDiscountActivity(@Valid @RequestBody DiscountActivityUpdateReqVO updateReqVO) {
  43 + discountActivityService.updateDiscountActivity(updateReqVO);
  44 + return success(true);
  45 + }
  46 +
  47 + @PutMapping("/close")
  48 + @ApiOperation("关闭限时折扣活动")
  49 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  50 + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:close')")
  51 + public CommonResult<Boolean> closeRewardActivity(@RequestParam("id") Long id) {
  52 + discountActivityService.closeRewardActivity(id);
  53 + return success(true);
  54 + }
  55 +
  56 + @DeleteMapping("/delete")
  57 + @ApiOperation("删除限时折扣活动")
  58 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  59 + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:delete')")
  60 + public CommonResult<Boolean> deleteDiscountActivity(@RequestParam("id") Long id) {
  61 + discountActivityService.deleteDiscountActivity(id);
  62 + return success(true);
  63 + }
  64 +
  65 + @GetMapping("/get")
  66 + @ApiOperation("获得限时折扣活动")
  67 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  68 + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
  69 + public CommonResult<DiscountActivityDetailRespVO> getDiscountActivity(@RequestParam("id") Long id) {
  70 + DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id);
  71 + if (discountActivity == null) {
  72 + return success(null);
  73 + }
  74 + // 拼接结果
  75 + List<DiscountProductDO> discountProducts = discountActivityService.getDiscountProductsByActivityId(id);
  76 + return success(DiscountActivityConvert.INSTANCE.convert(discountActivity, discountProducts));
  77 + }
  78 +
  79 + @GetMapping("/page")
  80 + @ApiOperation("获得限时折扣活动分页")
  81 + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
  82 + public CommonResult<PageResult<DiscountActivityRespVO>> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) {
  83 + PageResult<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(pageVO);
  84 + return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult));
  85 + }
  86 +
  87 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/package-info.java deleted
1 -/**  
2 - * TODO 占位  
3 - */  
4 -package cn.iocoder.yudao.module.promotion.controller.admin.discount;  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
  7 +import io.swagger.annotations.ApiModel;
  8 +import io.swagger.annotations.ApiModelProperty;
  9 +import lombok.Data;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import javax.validation.constraints.AssertTrue;
  13 +import javax.validation.constraints.Min;
  14 +import javax.validation.constraints.NotNull;
  15 +import java.util.Date;
  16 +
  17 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  18 +
  19 +/**
  20 +* 限时折扣活动 Base VO,提供给添加、修改、详细的子 VO 使用
  21 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  22 +*/
  23 +@Data
  24 +public class DiscountActivityBaseVO {
  25 +
  26 + @ApiModelProperty(value = "活动标题", required = true, example = "一个标题")
  27 + @NotNull(message = "活动标题不能为空")
  28 + private String name;
  29 +
  30 + @ApiModelProperty(value = "开始时间", required = true)
  31 + @NotNull(message = "开始时间不能为空")
  32 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  33 + private Date startTime;
  34 +
  35 + @ApiModelProperty(value = "结束时间", required = true)
  36 + @NotNull(message = "结束时间不能为空")
  37 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  38 + private Date endTime;
  39 +
  40 + @ApiModelProperty(value = "备注", example = "我是备注")
  41 + private String remark;
  42 +
  43 + @ApiModel("商品")
  44 + @Data
  45 + public static class Product {
  46 +
  47 + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1")
  48 + @NotNull(message = "商品 SPU 编号不能为空")
  49 + private Long spuId;
  50 +
  51 + @ApiModelProperty(value = "商品 SKU 编号", required = true, example = "1")
  52 + @NotNull(message = "商品 SKU 编号不能为空")
  53 + private Long skuId;
  54 +
  55 + @ApiModelProperty(value = "优惠类型", required = true, example = "1", notes = "参见 PromotionDiscountTypeEnum 枚举")
  56 + @NotNull(message = "优惠类型不能为空")
  57 + @InEnum(PromotionDiscountTypeEnum.class)
  58 + private Integer discountType;
  59 +
  60 + @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80")
  61 + private Integer discountPercent;
  62 +
  63 + @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分")
  64 + @Min(value = 0, message = "优惠金额需要大于等于 0")
  65 + private Integer discountPrice;
  66 +
  67 + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99")
  68 + @JsonIgnore
  69 + public boolean isDiscountPercentValid() {
  70 + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
  71 + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99);
  72 + }
  73 +
  74 + @AssertTrue(message = "优惠金额不能为空")
  75 + @JsonIgnore
  76 + public boolean isDiscountPriceValid() {
  77 + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PRICE.getType())
  78 + || discountPrice != null;
  79 + }
  80 +
  81 + }
  82 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import javax.validation.Valid;
  9 +import javax.validation.constraints.NotEmpty;
  10 +import java.util.List;
  11 +
  12 +@ApiModel("管理后台 - 限时折扣活动创建 Request VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class DiscountActivityCreateReqVO extends DiscountActivityBaseVO {
  17 +
  18 + /**
  19 + * 商品列表
  20 + */
  21 + @NotEmpty(message = "商品列表不能为空")
  22 + @Valid
  23 + private List<Product> products;
  24 +
  25 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityDetailRespVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import lombok.Data;
  5 +import lombok.EqualsAndHashCode;
  6 +import lombok.ToString;
  7 +
  8 +import java.util.List;
  9 +
  10 +@ApiModel("管理后台 - 限时折扣活动的详细 Response VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class DiscountActivityDetailRespVO extends DiscountActivityRespVO {
  15 +
  16 + /**
  17 + * 商品列表
  18 + */
  19 + private List<Product> products;
  20 +
  21 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityPageReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.annotations.*;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +
  9 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  10 +
  11 +@ApiModel("管理后台 - 限时折扣活动分页 Request VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class DiscountActivityPageReqVO extends PageParam {
  16 +
  17 + @ApiModelProperty(value = "活动标题", example = "一个标题")
  18 + private String name;
  19 +
  20 + @ApiModelProperty(value = "活动状态", example = "1")
  21 + private Integer status;
  22 +
  23 + @ApiModelProperty(value = "创建时间")
  24 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  25 + private Date[] createTime;
  26 +
  27 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.constraints.NotNull;
  10 +import java.util.Date;
  11 +
  12 +@ApiModel("管理后台 - 限时折扣活动 Response VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class DiscountActivityRespVO extends DiscountActivityBaseVO {
  17 +
  18 + @ApiModelProperty(value = "活动编号", required = true, example = "1024")
  19 + private Long id;
  20 +
  21 + @ApiModelProperty(value = "活动状态", required = true, example = "1")
  22 + @NotNull(message = "活动状态不能为空")
  23 + private Integer status;
  24 +
  25 + @ApiModelProperty(value = "创建时间", required = true)
  26 + private Date createTime;
  27 +
  28 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import javax.validation.Valid;
  10 +import javax.validation.constraints.NotEmpty;
  11 +import javax.validation.constraints.NotNull;
  12 +import java.util.List;
  13 +
  14 +@ApiModel("管理后台 - 限时折扣活动更新 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class DiscountActivityUpdateReqVO extends DiscountActivityBaseVO {
  19 +
  20 + @ApiModelProperty(value = "活动编号", required = true, example = "1024")
  21 + @NotNull(message = "活动编号不能为空")
  22 + private Long id;
  23 +
  24 + /**
  25 + * 商品列表
  26 + */
  27 + @NotEmpty(message = "商品列表不能为空")
  28 + @Valid
  29 + private List<DiscountActivityCreateReqVO.Product> products;
  30 +
  31 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.reward;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
  9 +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert;
  10 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
  11 +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
  12 +import io.swagger.annotations.Api;
  13 +import io.swagger.annotations.ApiImplicitParam;
  14 +import io.swagger.annotations.ApiOperation;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import javax.annotation.Resource;
  20 +import javax.validation.Valid;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +@Api(tags = "管理后台 - 满减送活动")
  25 +@RestController
  26 +@RequestMapping("/promotion/reward-activity")
  27 +@Validated
  28 +public class RewardActivityController {
  29 +
  30 + @Resource
  31 + private RewardActivityService rewardActivityService;
  32 +
  33 + @PostMapping("/create")
  34 + @ApiOperation("创建满减送活动")
  35 + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:create')")
  36 + public CommonResult<Long> createRewardActivity(@Valid @RequestBody RewardActivityCreateReqVO createReqVO) {
  37 + return success(rewardActivityService.createRewardActivity(createReqVO));
  38 + }
  39 +
  40 + @PutMapping("/update")
  41 + @ApiOperation("更新满减送活动")
  42 + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:update')")
  43 + public CommonResult<Boolean> updateRewardActivity(@Valid @RequestBody RewardActivityUpdateReqVO updateReqVO) {
  44 + rewardActivityService.updateRewardActivity(updateReqVO);
  45 + return success(true);
  46 + }
  47 +
  48 + @PutMapping("/close")
  49 + @ApiOperation("关闭满减送活动")
  50 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  51 + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:close')")
  52 + public CommonResult<Boolean> closeRewardActivity(@RequestParam("id") Long id) {
  53 + rewardActivityService.closeRewardActivity(id);
  54 + return success(true);
  55 + }
  56 +
  57 + @DeleteMapping("/delete")
  58 + @ApiOperation("删除满减送活动")
  59 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
  60 + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:delete')")
  61 + public CommonResult<Boolean> deleteRewardActivity(@RequestParam("id") Long id) {
  62 + rewardActivityService.deleteRewardActivity(id);
  63 + return success(true);
  64 + }
  65 +
  66 + @GetMapping("/get")
  67 + @ApiOperation("获得满减送活动")
  68 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  69 + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')")
  70 + public CommonResult<RewardActivityRespVO> getRewardActivity(@RequestParam("id") Long id) {
  71 + RewardActivityDO rewardActivity = rewardActivityService.getRewardActivity(id);
  72 + return success(RewardActivityConvert.INSTANCE.convert(rewardActivity));
  73 + }
  74 +
  75 + @GetMapping("/page")
  76 + @ApiOperation("获得满减送活动分页")
  77 + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')")
  78 + public CommonResult<PageResult<RewardActivityRespVO>> getRewardActivityPage(@Valid RewardActivityPageReqVO pageVO) {
  79 + PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(pageVO);
  80 + return success(RewardActivityConvert.INSTANCE.convertPage(pageResult));
  81 + }
  82 +
  83 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
  6 +import com.fasterxml.jackson.annotation.JsonIgnore;
  7 +import io.swagger.annotations.ApiModel;
  8 +import io.swagger.annotations.ApiModelProperty;
  9 +import lombok.Data;
  10 +import org.springframework.format.annotation.DateTimeFormat;
  11 +
  12 +import javax.validation.Valid;
  13 +import javax.validation.constraints.AssertTrue;
  14 +import javax.validation.constraints.Future;
  15 +import javax.validation.constraints.Min;
  16 +import javax.validation.constraints.NotNull;
  17 +import java.util.Date;
  18 +import java.util.List;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  21 +
  22 +/**
  23 +* 满减送活动 Base VO,提供给添加、修改、详细的子 VO 使用
  24 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  25 +*/
  26 +@Data
  27 +public class RewardActivityBaseVO {
  28 +
  29 + @ApiModelProperty(value = "活动标题", required = true, example = "满啦满啦")
  30 + @NotNull(message = "活动标题不能为空")
  31 + private String name;
  32 +
  33 + @ApiModelProperty(value = "开始时间", required = true)
  34 + @NotNull(message = "开始时间不能为空")
  35 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  36 + private Date startTime;
  37 +
  38 + @ApiModelProperty(value = "结束时间", required = true)
  39 + @NotNull(message = "结束时间不能为空")
  40 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  41 + @Future(message = "结束时间必须大于当前时间")
  42 + private Date endTime;
  43 +
  44 + @ApiModelProperty(value = "备注", example = "biubiubiu")
  45 + private String remark;
  46 +
  47 + @ApiModelProperty(value = "条件类型", required = true, example = "1")
  48 + @NotNull(message = "条件类型不能为空")
  49 + @InEnum(value = PromotionConditionTypeEnum.class, message = "条件类型必须是 {value}")
  50 + private Integer conditionType;
  51 +
  52 + @ApiModelProperty(value = "商品范围", required = true, example = "1")
  53 + @NotNull(message = "商品范围不能为空")
  54 + @InEnum(value = PromotionConditionTypeEnum.class, message = "商品范围必须是 {value}")
  55 + private Integer productScope;
  56 +
  57 + @ApiModelProperty(value = "商品 SPU 编号的数组", example = "1,2,3")
  58 + private List<Long> productSpuIds;
  59 +
  60 + /**
  61 + * 优惠规则的数组
  62 + */
  63 + @Valid // 校验下子对象
  64 + private List<Rule> rules;
  65 +
  66 + @ApiModel("优惠规则")
  67 + @Data
  68 + public static class Rule {
  69 +
  70 + @ApiModelProperty(value = "优惠门槛", required = true, example = "100", notes = "1. 满 N 元,单位:分; 2. 满 N 件")
  71 + @Min(value = 1L, message = "优惠门槛必须大于等于 1")
  72 + private Integer limit;
  73 +
  74 + @ApiModelProperty(value = "优惠价格", required = true, example = "100", notes = "单位:分")
  75 + @Min(value = 1L, message = "优惠价格必须大于等于 1")
  76 + private Integer discountPrice;
  77 +
  78 + @ApiModelProperty(value = "是否包邮", required = true, example = "true")
  79 + private Boolean freeDelivery;
  80 +
  81 + @ApiModelProperty(value = "赠送的积分", required = true, example = "100")
  82 + @Min(value = 1L, message = "赠送的积分必须大于等于 1")
  83 + private Integer point;
  84 +
  85 + @ApiModelProperty(value = "赠送的优惠劵编号的数组", example = "1,2,3")
  86 + private List<Long> couponIds;
  87 +
  88 + @ApiModelProperty(value = "赠送的优惠卷数量的数组", example = "1,2,3")
  89 + private List<Integer> couponCounts;
  90 +
  91 + @AssertTrue(message = "优惠劵和数量必须一一对应")
  92 + @JsonIgnore
  93 + public boolean isCouponCountsValid() {
  94 + return CollUtil.size(couponCounts) == CollUtil.size(couponCounts);
  95 + }
  96 +
  97 + }
  98 +
  99 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityCreateReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
  2 +
  3 +import lombok.*;
  4 +import io.swagger.annotations.*;
  5 +
  6 +@ApiModel("管理后台 - 满减送活动创建 Request VO")
  7 +@Data
  8 +@EqualsAndHashCode(callSuper = true)
  9 +@ToString(callSuper = true)
  10 +public class RewardActivityCreateReqVO extends RewardActivityBaseVO {
  11 +
  12 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityPageReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
  2 +
  3 +import lombok.*;
  4 +import io.swagger.annotations.*;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  6 +
  7 +@ApiModel("管理后台 - 满减送活动分页 Request VO")
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@ToString(callSuper = true)
  11 +public class RewardActivityPageReqVO extends PageParam {
  12 +
  13 + @ApiModelProperty(value = "活动标题", example = "满啦满啦")
  14 + private String name;
  15 +
  16 + @ApiModelProperty(value = "活动状态", example = "1")
  17 + private Integer status;
  18 +
  19 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityRespVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.annotations.*;
  6 +
  7 +@ApiModel("管理后台 - 满减送活动 Response VO")
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@ToString(callSuper = true)
  11 +public class RewardActivityRespVO extends RewardActivityBaseVO {
  12 +
  13 + @ApiModelProperty(value = "活动编号", required = true, example = "1024")
  14 + private Integer id;
  15 +
  16 + @ApiModelProperty(value = "活动状态", required = true, example = "1")
  17 + private Integer status;
  18 +
  19 + @ApiModelProperty(value = "创建时间", required = true)
  20 + private Date createTime;
  21 +
  22 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo;
  2 +
  3 +import lombok.*;
  4 +import io.swagger.annotations.*;
  5 +import javax.validation.constraints.*;
  6 +
  7 +@ApiModel("管理后台 - 满减送活动更新 Request VO")
  8 +@Data
  9 +@EqualsAndHashCode(callSuper = true)
  10 +@ToString(callSuper = true)
  11 +public class RewardActivityUpdateReqVO extends RewardActivityBaseVO {
  12 +
  13 + @ApiModelProperty(value = "活动编号", required = true, example = "1024")
  14 + @NotNull(message = "活动编号不能为空")
  15 + private Long id;
  16 +
  17 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.convert.coupon;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO;
  5 +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
  6 +import org.mapstruct.Mapper;
  7 +import org.mapstruct.factory.Mappers;
  8 +
  9 +/**
  10 + * 优惠劵 Convert
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@Mapper
  15 +public interface CouponConvert {
  16 +
  17 + CouponConvert INSTANCE = Mappers.getMapper(CouponConvert.class);
  18 +
  19 + PageResult<CouponPageItemRespVO> convertPage(PageResult<CouponDO> page);
  20 +
  21 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java
1 package cn.iocoder.yudao.module.promotion.convert.coupon; 1 package cn.iocoder.yudao.module.promotion.convert.coupon;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO;  
5 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateRespVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 4 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateRespVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
8 import org.mapstruct.Mapper; 8 import org.mapstruct.Mapper;
9 import org.mapstruct.factory.Mappers; 9 import org.mapstruct.factory.Mappers;
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.convert.discount;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
  9 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  10 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
  11 +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO;
  12 +import org.mapstruct.Mapper;
  13 +import org.mapstruct.factory.Mappers;
  14 +
  15 +import java.util.List;
  16 +import java.util.Map;
  17 +
  18 +/**
  19 + * 限时折扣活动 Convert
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Mapper
  24 +public interface DiscountActivityConvert {
  25 +
  26 + DiscountActivityConvert INSTANCE = Mappers.getMapper(DiscountActivityConvert.class);
  27 +
  28 + DiscountActivityDO convert(DiscountActivityCreateReqVO bean);
  29 +
  30 + DiscountActivityDO convert(DiscountActivityUpdateReqVO bean);
  31 +
  32 + DiscountActivityRespVO convert(DiscountActivityDO bean);
  33 +
  34 + List<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
  35 +
  36 + PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
  37 +
  38 + DiscountProductDetailBO convert(DiscountProductDO product);
  39 +
  40 + default List<DiscountProductDetailBO> convertList(List<DiscountProductDO> products, Map<Long, DiscountActivityDO> activityMap) {
  41 + return CollectionUtils.convertList(products, product -> {
  42 + DiscountProductDetailBO detail = convert(product);
  43 + MapUtils.findAndThen(activityMap, product.getActivityId(), activity -> {
  44 + detail.setActivityName(activity.getName());
  45 + });
  46 + return detail;
  47 + });
  48 + }
  49 +
  50 + DiscountProductDO convert(DiscountActivityBaseVO.Product bean);
  51 +
  52 + DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List<DiscountProductDO> products);
  53 +
  54 + // =========== 比较是否相等 ==========
  55 + /**
  56 + * 比较两个限时折扣商品是否相等
  57 + *
  58 + * @param productDO 数据库中的商品
  59 + * @param productVO 前端传入的商品
  60 + * @return 是否匹配
  61 + */
  62 + @SuppressWarnings("DuplicatedCode")
  63 + default boolean isEquals(DiscountProductDO productDO, DiscountActivityBaseVO.Product productVO) {
  64 + if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())
  65 + || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())
  66 + || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) {
  67 + return false;
  68 + }
  69 + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {
  70 + return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());
  71 + }
  72 + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {
  73 + return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());
  74 + }
  75 + return true;
  76 + }
  77 +
  78 + /**
  79 + * 比较两个限时折扣商品是否相等
  80 + * 注意,比较时忽略 id 编号
  81 + *
  82 + * @param productDO 商品 1
  83 + * @param productVO 商品 2
  84 + * @return 是否匹配
  85 + */
  86 + @SuppressWarnings("DuplicatedCode")
  87 + default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) {
  88 + if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId())
  89 + || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId())
  90 + || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) {
  91 + return false;
  92 + }
  93 + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) {
  94 + return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice());
  95 + }
  96 + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) {
  97 + return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent());
  98 + }
  99 + return true;
  100 + }
  101 +
  102 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/package-info.java deleted
1 -/**  
2 - * TODO 占位  
3 - */  
4 -package cn.iocoder.yudao.module.promotion.convert.discount;  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/price/PriceConvert.java
@@ -36,7 +36,8 @@ public interface PriceConvert { @@ -36,7 +36,8 @@ public interface PriceConvert {
36 orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice()); 36 orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice());
37 priceCalculate.getOrder().getItems().add(orderItem); 37 priceCalculate.getOrder().getItems().add(orderItem);
38 // 补充价格信息到 Order 中 38 // 补充价格信息到 Order 中
39 - order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice()).setPayPrice(order.getOriginalPrice()); 39 + order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice())
  40 + .setOrderPrice(order.getOriginalPrice()).setPayPrice(order.getOriginalPrice());
40 }); 41 });
41 return priceCalculate; 42 return priceCalculate;
42 } 43 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.convert.reward;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
  8 +import org.mapstruct.Mapper;
  9 +import org.mapstruct.factory.Mappers;
  10 +
  11 +/**
  12 + * 满减送活动 Convert
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Mapper
  17 +public interface RewardActivityConvert {
  18 +
  19 + RewardActivityConvert INSTANCE = Mappers.getMapper(RewardActivityConvert.class);
  20 +
  21 + RewardActivityDO convert(RewardActivityCreateReqVO bean);
  22 +
  23 + RewardActivityDO convert(RewardActivityUpdateReqVO bean);
  24 +
  25 + RewardActivityRespVO convert(RewardActivityDO bean);
  26 +
  27 + PageResult<RewardActivityRespVO> convertPage(PageResult<RewardActivityDO> page);
  28 +
  29 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java
1 package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon; 1 package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
  5 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
4 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; 6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
  7 +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
  8 +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum;
5 import com.baomidou.mybatisplus.annotation.KeySequence; 9 import com.baomidou.mybatisplus.annotation.KeySequence;
6 import com.baomidou.mybatisplus.annotation.TableField; 10 import com.baomidou.mybatisplus.annotation.TableField;
7 import com.baomidou.mybatisplus.annotation.TableName; 11 import com.baomidou.mybatisplus.annotation.TableName;
8 -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;  
9 import lombok.Data; 12 import lombok.Data;
10 import lombok.EqualsAndHashCode; 13 import lombok.EqualsAndHashCode;
11 14
@@ -14,9 +17,11 @@ import java.util.List; @@ -14,9 +17,11 @@ import java.util.List;
14 17
15 /** 18 /**
16 * 优惠劵 DO 19 * 优惠劵 DO
  20 + *
  21 + * @author 芋道源码
17 */ 22 */
18 @TableName(value = "promotion_coupon", autoResultMap = true) 23 @TableName(value = "promotion_coupon", autoResultMap = true)
19 -@KeySequence("promotion_coupo_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 24 +@KeySequence("promotion_coupon_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
20 @Data 25 @Data
21 @EqualsAndHashCode(callSuper = true) 26 @EqualsAndHashCode(callSuper = true)
22 public class CouponDO extends BaseDO { 27 public class CouponDO extends BaseDO {
@@ -35,21 +40,13 @@ public class CouponDO extends BaseDO { @@ -35,21 +40,13 @@ public class CouponDO extends BaseDO {
35 /** 40 /**
36 * 优惠劵名 41 * 优惠劵名
37 * 42 *
38 - * 冗余自 {@link CouponTemplateDO} 的 title  
39 - *  
40 - * TODO 芋艿,暂时不考虑冗余的更新 43 + * 冗余 {@link CouponTemplateDO#getName()}
41 */ 44 */
42 - private String title;  
43 -// /**  
44 -// * 核销码  
45 -// */  
46 -// private String verifyCode; 45 + private String name;
47 /** 46 /**
48 * 优惠码状态 47 * 优惠码状态
49 * 48 *
50 - * 1-未使用  
51 - * 2-已使用  
52 - * 3-已失效 49 + * 枚举 {@link CouponStatusEnum}
53 */ 50 */
54 private Integer status; 51 private Integer status;
55 52
@@ -58,13 +55,14 @@ public class CouponDO extends BaseDO { @@ -58,13 +55,14 @@ public class CouponDO extends BaseDO {
58 // ========== 领取情况 BEGIN ========== 55 // ========== 领取情况 BEGIN ==========
59 /** 56 /**
60 * 用户编号 57 * 用户编号
  58 + *
  59 + * 关联 MemberUserDO 的 id 字段
61 */ 60 */
62 - private Integer userId; 61 + private Long userId;
63 /** 62 /**
64 * 领取类型 63 * 领取类型
65 * 64 *
66 - * 1 - 用户主动领取  
67 - * 2 - 后台自动发放 65 + * 枚举 {@link CouponTakeTypeEnum}
68 */ 66 */
69 private Integer takeType; 67 private Integer takeType;
70 // ========== 领取情况 END ========== 68 // ========== 领取情况 END ==========
@@ -72,8 +70,10 @@ public class CouponDO extends BaseDO { @@ -72,8 +70,10 @@ public class CouponDO extends BaseDO {
72 // ========== 使用规则 BEGIN ========== 70 // ========== 使用规则 BEGIN ==========
73 /** 71 /**
74 * 是否设置满多少金额可用,单位:分 72 * 是否设置满多少金额可用,单位:分
  73 + *
  74 + * 冗余 {@link CouponTemplateDO#getUsePrice()}
75 */ 75 */
76 - private Integer priceAvailable; 76 + private Integer usePrice;
77 /** 77 /**
78 * 生效开始时间 78 * 生效开始时间
79 */ 79 */
@@ -90,50 +90,49 @@ public class CouponDO extends BaseDO { @@ -90,50 +90,49 @@ public class CouponDO extends BaseDO {
90 private Integer productScope; 90 private Integer productScope;
91 /** 91 /**
92 * 商品 SPU 编号的数组 92 * 商品 SPU 编号的数组
  93 + *
  94 + * 冗余 {@link CouponTemplateDO#getProductSpuIds()}
93 */ 95 */
94 - @TableField(typeHandler = JacksonTypeHandler.class)  
95 - private List<Long> spuIds; 96 + @TableField(typeHandler = LongListTypeHandler.class)
  97 + private List<Long> productSpuIds;
96 // ========== 使用规则 END ========== 98 // ========== 使用规则 END ==========
97 99
98 // ========== 使用效果 BEGIN ========== 100 // ========== 使用效果 BEGIN ==========
99 /** 101 /**
100 - * 优惠类型 102 + * 折扣类型
101 * 103 *
102 - * 1-代金卷  
103 - * 2-折扣卷 104 + * 冗余 {@link CouponTemplateDO#getDiscountType()}
104 */ 105 */
105 - private Integer preferentialType; 106 + private Integer discountType;
106 /** 107 /**
107 - * 折扣 108 + * 折扣百分比
  109 + *
  110 + * 冗余 {@link CouponTemplateDO#getDiscountPercent()}
108 */ 111 */
109 - private Integer percentOff; 112 + private Integer discountPercent;
110 /** 113 /**
111 - * 优惠金额,单位:分。 114 + * 优惠金额,单位:分
  115 + *
  116 + * 冗余 {@link CouponTemplateDO#getDiscountPrice()}
112 */ 117 */
113 - private Integer priceOff; 118 + private Integer discountPrice;
114 /** 119 /**
115 - * 折扣上限,仅在 {@link #preferentialType} 等于 2 时生效。 120 + * 折扣上限,仅在 {@link #discountType} 等于 {@link PromotionDiscountTypeEnum#PERCENT} 时生效
116 * 121 *
117 - * 例如,折扣上限为 20 元,当使用 8 折优惠券,订单金额为 1000 元时,最高只可折扣 20 元,而非 80 元。 122 + * 冗余 {@link CouponTemplateDO#getDiscountLimitPrice()}
118 */ 123 */
119 - private Integer discountPriceLimit; 124 + private Integer discountLimitPrice;
120 // ========== 使用效果 END ========== 125 // ========== 使用效果 END ==========
121 126
122 // ========== 使用情况 BEGIN ========== 127 // ========== 使用情况 BEGIN ==========
123 -// /**  
124 -// * 使用订单号  
125 -// */  
126 -// private Integer usedOrderId; // TODO 芋艿,暂时不考虑这个字段  
127 -// /**  
128 -// * 订单中优惠面值,单位:分  
129 -// */  
130 -// private Integer usedPrice; // TODO 芋艿,暂时不考虑这个字段 128 + /**
  129 + * 使用订单号
  130 + */
  131 + private Long useOrderId;
131 /** 132 /**
132 * 使用时间 133 * 使用时间
133 */ 134 */
134 - private Date usedTime;  
135 -  
136 - // TODO 芋艿,后续要加优惠劵的使用日志,因为下单后,可能会取消。 135 + private Date useTime;
137 136
138 // ========== 使用情况 END ========== 137 // ========== 使用情况 END ==========
139 138
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java
@@ -21,6 +21,8 @@ import java.util.List; @@ -21,6 +21,8 @@ import java.util.List;
21 * 优惠劵模板 DO 21 * 优惠劵模板 DO
22 * 22 *
23 * 当用户领取时,会生成 {@link CouponDO} 优惠劵 23 * 当用户领取时,会生成 {@link CouponDO} 优惠劵
  24 + *
  25 + * @author 芋道源码
24 */ 26 */
25 @TableName(value = "promotion_coupon_template", autoResultMap = true) 27 @TableName(value = "promotion_coupon_template", autoResultMap = true)
26 @KeySequence("promotion_coupon_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 28 @KeySequence("promotion_coupon_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java
1 package cn.iocoder.yudao.module.promotion.dal.dataobject.discount; 1 package cn.iocoder.yudao.module.promotion.dal.dataobject.discount;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
4 import com.baomidou.mybatisplus.annotation.KeySequence; 5 import com.baomidou.mybatisplus.annotation.KeySequence;
5 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
6 import com.baomidou.mybatisplus.annotation.TableName; 7 import com.baomidou.mybatisplus.annotation.TableName;
7 import lombok.Data; 8 import lombok.Data;
8 import lombok.EqualsAndHashCode; 9 import lombok.EqualsAndHashCode;
9 10
10 -import java.util.Date;  
11 -  
12 /** 11 /**
13 * 限时折扣商品 DO 12 * 限时折扣商品 DO
14 * 13 *
@@ -32,12 +31,6 @@ public class DiscountProductDO extends BaseDO { @@ -32,12 +31,6 @@ public class DiscountProductDO extends BaseDO {
32 */ 31 */
33 private Long activityId; 32 private Long activityId;
34 /** 33 /**
35 - * 限时折扣活动的名字  
36 - *  
37 - * 冗余 {@link DiscountActivityDO#getName()}  
38 - */  
39 - private String activityName;  
40 - /**  
41 * 商品 SPU 编号 34 * 商品 SPU 编号
42 * 35 *
43 * 关联 ProductSpuDO 的 id 编号 36 * 关联 ProductSpuDO 的 id 编号
@@ -49,23 +42,24 @@ public class DiscountProductDO extends BaseDO { @@ -49,23 +42,24 @@ public class DiscountProductDO extends BaseDO {
49 * 关联 ProductSkuDO 的 id 编号 42 * 关联 ProductSkuDO 的 id 编号
50 */ 43 */
51 private Long skuId; 44 private Long skuId;
  45 +
52 /** 46 /**
53 - * 开始时间  
54 - */  
55 - private Date startTime;  
56 - /**  
57 - * 结束时间 47 + * 折扣类型
  48 + *
  49 + * 枚举 {@link PromotionDiscountTypeEnum}
58 */ 50 */
59 - private Date endTime; 51 + private Integer discountType;
60 /** 52 /**
61 - * 销售价格,单位:分 53 + * 折扣百分比
62 * 54 *
63 - * 冗余 ProductSkuDO 的 price 字段 55 + * 例如,80% 为 80
64 */ 56 */
65 - private Integer originalPrice; 57 + private Integer discountPercent;
66 /** 58 /**
67 - * 优惠价格,单位:分 59 + * 优惠金额,单位:分
  60 + *
  61 + * 当 {@link #discountType} 为 {@link PromotionDiscountTypeEnum#PRICE} 生效
68 */ 62 */
69 - private Integer promotionPrice; 63 + private Integer discountPrice;
70 64
71 } 65 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java
1 package cn.iocoder.yudao.module.promotion.dal.dataobject.reward; 1 package cn.iocoder.yudao.module.promotion.dal.dataobject.reward;
2 2
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
4 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; 6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
5 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; 7 import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
6 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; 8 import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
@@ -8,10 +10,11 @@ import com.baomidou.mybatisplus.annotation.KeySequence; @@ -8,10 +10,11 @@ import com.baomidou.mybatisplus.annotation.KeySequence;
8 import com.baomidou.mybatisplus.annotation.TableField; 10 import com.baomidou.mybatisplus.annotation.TableField;
9 import com.baomidou.mybatisplus.annotation.TableId; 11 import com.baomidou.mybatisplus.annotation.TableId;
10 import com.baomidou.mybatisplus.annotation.TableName; 12 import com.baomidou.mybatisplus.annotation.TableName;
11 -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; 13 +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler;
12 import lombok.Data; 14 import lombok.Data;
13 import lombok.EqualsAndHashCode; 15 import lombok.EqualsAndHashCode;
14 16
  17 +import java.io.Serializable;
15 import java.util.Date; 18 import java.util.Date;
16 import java.util.List; 19 import java.util.List;
17 20
@@ -68,19 +71,19 @@ public class RewardActivityDO extends BaseDO { @@ -68,19 +71,19 @@ public class RewardActivityDO extends BaseDO {
68 /** 71 /**
69 * 商品 SPU 编号的数组 72 * 商品 SPU 编号的数组
70 */ 73 */
71 - @TableField(typeHandler = JacksonTypeHandler.class) 74 + @TableField(typeHandler = LongListTypeHandler.class)
72 private List<Long> productSpuIds; 75 private List<Long> productSpuIds;
73 /** 76 /**
74 * 优惠规则的数组 77 * 优惠规则的数组
75 */ 78 */
76 - @TableField(typeHandler = JacksonTypeHandler.class) 79 + @TableField(typeHandler = RuleTypeHandler.class)
77 private List<Rule> rules; 80 private List<Rule> rules;
78 81
79 /** 82 /**
80 * 优惠规则 83 * 优惠规则
81 */ 84 */
82 @Data 85 @Data
83 - public static class Rule { 86 + public static class Rule implements Serializable {
84 87
85 /** 88 /**
86 * 优惠门槛 89 * 优惠门槛
@@ -112,5 +115,19 @@ public class RewardActivityDO extends BaseDO { @@ -112,5 +115,19 @@ public class RewardActivityDO extends BaseDO {
112 115
113 } 116 }
114 117
  118 + // TODO @芋艿:可以找一些新的思路
  119 + public static class RuleTypeHandler extends AbstractJsonTypeHandler<List<Rule>> {
  120 +
  121 + @Override
  122 + protected List<Rule> parse(String json) {
  123 + return JsonUtils.parseArray(json, Rule.class);
  124 + }
  125 +
  126 + @Override
  127 + protected String toJson(List<Rule> obj) {
  128 + return JsonUtils.toJsonString(obj);
  129 + }
  130 +
  131 + }
115 132
116 } 133 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.dal.mysql.coupon;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
  8 +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +import java.util.Collection;
  12 +
  13 +/**
  14 + * 优惠劵 Mapper
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Mapper
  19 +public interface CouponMapper extends BaseMapperX<CouponDO> {
  20 +
  21 + default PageResult<CouponDO> selectPage(CouponPageReqVO reqVO, Collection<Long> userIds) {
  22 + return selectPage(reqVO, new LambdaQueryWrapperX<CouponDO>()
  23 + .eqIfPresent(CouponDO::getTemplateId, reqVO.getTemplateId())
  24 + .eqIfPresent(CouponDO::getStatus, reqVO.getStatus())
  25 + .inIfPresent(CouponDO::getUserId, userIds)
  26 + .betweenIfPresent(CouponDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(CouponDO::getId));
  28 + }
  29 +
  30 + default int delete(Long id, Collection<Integer> whereStatuses) {
  31 + return update(null, new LambdaUpdateWrapper<CouponDO>()
  32 + .eq(CouponDO::getId, id).in(CouponDO::getStatus, whereStatuses)
  33 + .set(CouponDO::getDeleted, 1));
  34 + }
  35 +
  36 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java
@@ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; @@ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.coupon;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO; 6 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
  9 +import org.apache.ibatis.annotations.Param;
9 10
10 /** 11 /**
11 * 优惠劵模板 Mapper 12 * 优惠劵模板 Mapper
@@ -24,4 +25,6 @@ public interface CouponTemplateMapper extends BaseMapperX&lt;CouponTemplateDO&gt; { @@ -24,4 +25,6 @@ public interface CouponTemplateMapper extends BaseMapperX&lt;CouponTemplateDO&gt; {
24 .orderByDesc(CouponTemplateDO::getId)); 25 .orderByDesc(CouponTemplateDO::getId));
25 } 26 }
26 27
  28 + void updateTakeCount(@Param("id") Long id, @Param("incrCount") Integer incrCount);
  29 +
27 } 30 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +import java.util.Set;
  13 +
  14 +/**
  15 + * 限时折扣活动 Mapper
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@Mapper
  20 +public interface DiscountActivityMapper extends BaseMapperX<DiscountActivityDO> {
  21 +
  22 + default PageResult<DiscountActivityDO> selectPage(DiscountActivityPageReqVO reqVO) {
  23 + return selectPage(reqVO, new LambdaQueryWrapperX<DiscountActivityDO>()
  24 + .likeIfPresent(DiscountActivityDO::getName, reqVO.getName())
  25 + .eqIfPresent(DiscountActivityDO::getStatus, reqVO.getStatus())
  26 + .betweenIfPresent(DiscountActivityDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(DiscountActivityDO::getId));
  28 + }
  29 +
  30 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  5 +import org.apache.ibatis.annotations.Mapper;
  6 +
  7 +import java.util.Collection;
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * 限时折扣商城 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface DiscountProductMapper extends BaseMapperX<DiscountProductDO> {
  17 +
  18 + default List<DiscountProductDO> selectListBySkuId(Collection<Long> skuIds) {
  19 + return selectList(DiscountProductDO::getSkuId, skuIds);
  20 + }
  21 +
  22 + default List<DiscountProductDO> selectListByActivityId(Long activityId) {
  23 + return selectList(DiscountProductDO::getActivityId, activityId);
  24 + }
  25 +
  26 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/package-info.java deleted
1 -/**  
2 - * TODO 占位  
3 - */  
4 -package cn.iocoder.yudao.module.promotion.dal.mysql.discount;  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.dal.mysql.reward;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * 满减送活动 Mapper
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Mapper
  19 +public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> {
  20 +
  21 + default PageResult<RewardActivityDO> selectPage(RewardActivityPageReqVO reqVO) {
  22 + return selectPage(reqVO, new LambdaQueryWrapperX<RewardActivityDO>()
  23 + .likeIfPresent(RewardActivityDO::getName, reqVO.getName())
  24 + .eqIfPresent(RewardActivityDO::getStatus, reqVO.getStatus())
  25 + .orderByDesc(RewardActivityDO::getId));
  26 + }
  27 +
  28 + default List<RewardActivityDO> selectListByStatus(Collection<Integer> statuses) {
  29 + return selectList(RewardActivityDO::getStatus, statuses);
  30 + }
  31 +
  32 + default List<RewardActivityDO> selectListByProductScopeAndStatus(Integer productScope, Integer status) {
  33 + return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
  34 + .eq(RewardActivityDO::getProductScope, productScope)
  35 + .eq(RewardActivityDO::getStatus, status));
  36 + }
  37 +
  38 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java
1 package cn.iocoder.yudao.module.promotion.service.coupon; 1 package cn.iocoder.yudao.module.promotion.service.coupon;
2 2
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
3 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; 5 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
4 6
5 /** 7 /**
@@ -21,4 +23,19 @@ public interface CouponService { @@ -21,4 +23,19 @@ public interface CouponService {
21 */ 23 */
22 CouponDO validCoupon(Long id, Long userId); 24 CouponDO validCoupon(Long id, Long userId);
23 25
  26 + /**
  27 + * 获得优惠劵分页
  28 + *
  29 + * @param pageReqVO 分页查询
  30 + * @return 优惠劵分页
  31 + */
  32 + PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO);
  33 +
  34 + /**
  35 + * 回收优惠劵
  36 + *
  37 + * @param id 优惠劵编号
  38 + */
  39 + void deleteCoupon(Long id);
  40 +
24 } 41 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java
1 package cn.iocoder.yudao.module.promotion.service.coupon; 1 package cn.iocoder.yudao.module.promotion.service.coupon;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
  8 +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
  9 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO;
3 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; 10 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
  11 +import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper;
  12 +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
4 import org.springframework.stereotype.Service; 13 import org.springframework.stereotype.Service;
  14 +import org.springframework.transaction.annotation.Transactional;
5 import org.springframework.validation.annotation.Validated; 15 import org.springframework.validation.annotation.Validated;
6 16
  17 +import javax.annotation.Resource;
  18 +import java.util.Set;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  21 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_DELETE_FAIL_USED;
  22 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NOT_EXISTS;
  23 +import static java.util.Arrays.asList;
  24 +
7 /** 25 /**
8 * 优惠劵 Service 实现类 26 * 优惠劵 Service 实现类
9 * 27 *
@@ -13,9 +31,56 @@ import org.springframework.validation.annotation.Validated; @@ -13,9 +31,56 @@ import org.springframework.validation.annotation.Validated;
13 @Validated 31 @Validated
14 public class CouponServiceImpl implements CouponService { 32 public class CouponServiceImpl implements CouponService {
15 33
  34 + @Resource
  35 + private CouponTemplateService couponTemplateService;
  36 +
  37 + @Resource
  38 + private CouponMapper couponMapper;
  39 +
  40 + @Resource
  41 + private MemberUserApi memberUserApi;
  42 +
16 // TODO 芋艿:待实现 43 // TODO 芋艿:待实现
17 @Override 44 @Override
18 public CouponDO validCoupon(Long id, Long userId) { 45 public CouponDO validCoupon(Long id, Long userId) {
19 return null; 46 return null;
20 } 47 }
  48 +
  49 + @Override
  50 + public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) {
  51 + // 获得用户编号
  52 + Set<Long> userIds = null;
  53 + if (StrUtil.isNotEmpty(pageReqVO.getNickname())) {
  54 + userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageReqVO.getNickname()),
  55 + UserRespDTO::getId);
  56 + if (CollUtil.isEmpty(userIds)) {
  57 + return PageResult.empty();
  58 + }
  59 + }
  60 + // 分页查询
  61 + return couponMapper.selectPage(pageReqVO, userIds);
  62 + }
  63 +
  64 + @Override
  65 + @Transactional
  66 + public void deleteCoupon(Long id) {
  67 + // 校验存在
  68 + validateCouponExists(id);
  69 +
  70 + // 更新优惠劵
  71 + int deleteCount = couponMapper.delete(id,
  72 + asList(CouponStatusEnum.UNUSED.getStatus(), CouponStatusEnum.EXPIRE.getStatus()));
  73 + if (deleteCount == 0) {
  74 + throw exception(COUPON_DELETE_FAIL_USED);
  75 + }
  76 + // 减少优惠劵模板的领取数量 -1
  77 + couponTemplateService.updateCouponTemplateTakeCount(id, -1);
  78 + }
  79 +
  80 + private void validateCouponExists(Long id) {
  81 + if (couponMapper.selectById(id) == null) {
  82 + throw exception(COUPON_NOT_EXISTS);
  83 + }
  84 + }
  85 +
21 } 86 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java
1 package cn.iocoder.yudao.module.promotion.service.coupon; 1 package cn.iocoder.yudao.module.promotion.service.coupon;
2 2
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO;  
5 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 4 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; 7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
8 8
9 import javax.validation.Valid; 9 import javax.validation.Valid;
@@ -31,6 +31,14 @@ public interface CouponTemplateService { @@ -31,6 +31,14 @@ public interface CouponTemplateService {
31 void updateCouponTemplate(@Valid CouponTemplateUpdateReqVO updateReqVO); 31 void updateCouponTemplate(@Valid CouponTemplateUpdateReqVO updateReqVO);
32 32
33 /** 33 /**
  34 + * 更新优惠劵模板的状态
  35 + *
  36 + * @param id 编号
  37 + * @param status 状态
  38 + */
  39 + void updateCouponTemplateStatus(Long id, Integer status);
  40 +
  41 + /**
34 * 删除优惠劵模板 42 * 删除优惠劵模板
35 * 43 *
36 * @param id 编号 44 * @param id 编号
@@ -53,4 +61,12 @@ public interface CouponTemplateService { @@ -53,4 +61,12 @@ public interface CouponTemplateService {
53 */ 61 */
54 PageResult<CouponTemplateDO> getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO); 62 PageResult<CouponTemplateDO> getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO);
55 63
  64 + /**
  65 + * 更新优惠劵模板的领取数量
  66 + *
  67 + * @param id 优惠劵模板编号
  68 + * @param incrCount 增加数量
  69 + */
  70 + void updateCouponTemplateTakeCount(Long id, int incrCount);
  71 +
56 } 72 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java
1 package cn.iocoder.yudao.module.promotion.service.coupon; 1 package cn.iocoder.yudao.module.promotion.service.coupon;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO;  
5 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 5 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
7 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; 8 import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
9 import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; 10 import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper;
@@ -30,7 +31,8 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { @@ -30,7 +31,8 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
30 @Override 31 @Override
31 public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) { 32 public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) {
32 // 插入 33 // 插入
33 - CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO); 34 + CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO)
  35 + .setStatus(CommonStatusEnum.ENABLE.getStatus());
34 couponTemplateMapper.insert(couponTemplate); 36 couponTemplateMapper.insert(couponTemplate);
35 // 返回 37 // 返回
36 return couponTemplate.getId(); 38 return couponTemplate.getId();
@@ -51,6 +53,14 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { @@ -51,6 +53,14 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
51 } 53 }
52 54
53 @Override 55 @Override
  56 + public void updateCouponTemplateStatus(Long id, Integer status) {
  57 + // 校验存在
  58 + validateCouponTemplateExists(id);
  59 + // 更新
  60 + couponTemplateMapper.updateById(new CouponTemplateDO().setId(id).setStatus(status));
  61 + }
  62 +
  63 + @Override
54 public void deleteCouponTemplate(Long id) { 64 public void deleteCouponTemplate(Long id) {
55 // 校验存在 65 // 校验存在
56 validateCouponTemplateExists(id); 66 validateCouponTemplateExists(id);
@@ -76,4 +86,9 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { @@ -76,4 +86,9 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
76 return couponTemplateMapper.selectPage(pageReqVO); 86 return couponTemplateMapper.selectPage(pageReqVO);
77 } 87 }
78 88
  89 + @Override
  90 + public void updateCouponTemplateTakeCount(Long id, int incrCount) {
  91 + couponTemplateMapper.updateTakeCount(id, incrCount);
  92 + }
  93 +
79 } 94 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.discount;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  9 +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO;
  10 +
  11 +import javax.validation.Valid;
  12 +import java.util.Collection;
  13 +import java.util.List;
  14 +import java.util.Map;
  15 +
  16 +/**
  17 + * 限时折扣 Service 接口
  18 + *
  19 + * @author 芋道源码
  20 + */
  21 +public interface DiscountActivityService {
  22 +
  23 + /**
  24 + * 基于指定 SKU 编号数组,获得匹配的限时折扣商品
  25 + *
  26 + * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态
  27 + *
  28 + * @param skuIds SKU 编号数组
  29 + * @return 匹配的限时折扣商品
  30 + */
  31 + Map<Long, DiscountProductDetailBO> getMatchDiscountProducts(Collection<Long> skuIds);
  32 +
  33 + /**
  34 + * 创建限时折扣活动
  35 + *
  36 + * @param createReqVO 创建信息
  37 + * @return 编号
  38 + */
  39 + Long createDiscountActivity(@Valid DiscountActivityCreateReqVO createReqVO);
  40 +
  41 + /**
  42 + * 更新限时折扣活动
  43 + *
  44 + * @param updateReqVO 更新信息
  45 + */
  46 + void updateDiscountActivity(@Valid DiscountActivityUpdateReqVO updateReqVO);
  47 +
  48 + /**
  49 + * 关闭限时折扣活动
  50 + *
  51 + * @param id 编号
  52 + */
  53 + void closeRewardActivity(Long id);
  54 +
  55 + /**
  56 + * 删除限时折扣活动
  57 + *
  58 + * @param id 编号
  59 + */
  60 + void deleteDiscountActivity(Long id);
  61 +
  62 + /**
  63 + * 获得限时折扣活动
  64 + *
  65 + * @param id 编号
  66 + * @return 限时折扣活动
  67 + */
  68 + DiscountActivityDO getDiscountActivity(Long id);
  69 +
  70 + /**
  71 + * 获得限时折扣活动分页
  72 + *
  73 + * @param pageReqVO 分页查询
  74 + * @return 限时折扣活动分页
  75 + */
  76 + PageResult<DiscountActivityDO> getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO);
  77 +
  78 + /**
  79 + * 获得活动编号,对应对应的商品列表
  80 + *
  81 + * @param activityId 活动编号
  82 + * @return 活动的商品列表
  83 + */
  84 + List<DiscountProductDO> getDiscountProductsByActivityId(Long activityId);
  85 +
  86 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.service.discount;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.collection.CollectionUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
  9 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
  10 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
  11 +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
  12 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
  13 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  14 +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper;
  15 +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
  16 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  17 +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO;
  18 +import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
  19 +import org.springframework.stereotype.Service;
  20 +import org.springframework.validation.annotation.Validated;
  21 +
  22 +import javax.annotation.Resource;
  23 +import java.util.*;
  24 +
  25 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  26 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  27 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
  28 +import static java.util.Arrays.asList;
  29 +
  30 +/**
  31 + * 限时折扣 Service 实现类
  32 + *
  33 + * @author 芋道源码
  34 + */
  35 +@Service
  36 +@Validated
  37 +public class DiscountActivityServiceImpl implements DiscountActivityService {
  38 +
  39 + @Resource
  40 + private DiscountActivityMapper discountActivityMapper;
  41 + @Resource
  42 + private DiscountProductMapper discountProductMapper;
  43 +
  44 + @Override
  45 + public Map<Long, DiscountProductDetailBO> getMatchDiscountProducts(Collection<Long> skuIds) {
  46 + List<DiscountProductDetailBO> discountProducts = getRewardProductListBySkuIds(skuIds, singleton(PromotionActivityStatusEnum.RUN.getStatus()));
  47 + return convertMap(discountProducts, DiscountProductDetailBO::getSkuId);
  48 + }
  49 +
  50 + @Override
  51 + public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) {
  52 + // 校验商品是否冲突
  53 + validateDiscountActivityProductConflicts(null, createReqVO.getProducts());
  54 +
  55 + // 插入活动
  56 + DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO)
  57 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
  58 + discountActivityMapper.insert(discountActivity);
  59 + // 插入商品
  60 + List<DiscountProductDO> discountProducts = convertList(createReqVO.getProducts(),
  61 + product -> DiscountActivityConvert.INSTANCE.convert(product).setActivityId(discountActivity.getId()));
  62 + discountProductMapper.insertBatch(discountProducts);
  63 + // 返回
  64 + return discountActivity.getId();
  65 + }
  66 +
  67 + @Override
  68 + public void updateDiscountActivity(DiscountActivityUpdateReqVO updateReqVO) {
  69 + // 校验存在
  70 + DiscountActivityDO discountActivity = validateDiscountActivityExists(updateReqVO.getId());
  71 + if (discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢
  72 + throw exception(DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
  73 + }
  74 + // 校验商品是否冲突
  75 + validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts());
  76 +
  77 + // 更新活动
  78 + DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO)
  79 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
  80 + discountActivityMapper.updateById(updateObj);
  81 + // 更新商品
  82 + updateDiscountProduct(updateReqVO);
  83 + }
  84 +
  85 + private void updateDiscountProduct(DiscountActivityUpdateReqVO updateReqVO) {
  86 + List<DiscountProductDO> dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId());
  87 + // 计算要删除的记录
  88 + List<Long> deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId,
  89 + discountProductDO -> updateReqVO.getProducts().stream()
  90 + .noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product)));
  91 + if (CollUtil.isNotEmpty(deleteIds)) {
  92 + discountProductMapper.deleteBatchIds(deleteIds);
  93 + }
  94 + // 计算新增的记录
  95 + List<DiscountProductDO> newDiscountProducts = convertList(updateReqVO.getProducts(),
  96 + product -> DiscountActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId()));
  97 + newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch(
  98 + dbProduct -> DiscountActivityConvert.INSTANCE.isEquals(dbProduct, product))); // 如果匹配到,说明是更新的
  99 + if (CollectionUtil.isNotEmpty(newDiscountProducts)) {
  100 + discountProductMapper.insertBatch(newDiscountProducts);
  101 + }
  102 + }
  103 +
  104 + /**
  105 + * 校验商品是否冲突
  106 + *
  107 + * @param id 编号
  108 + * @param products 商品列表
  109 + */
  110 + private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) {
  111 + if (CollUtil.isEmpty(products)) {
  112 + return;
  113 + }
  114 + // 查询商品参加的活动
  115 + List<DiscountProductDetailBO> discountActivityProductList = getRewardProductListBySkuIds(
  116 + convertSet(products, DiscountActivityBaseVO.Product::getSkuId),
  117 + asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus()));
  118 + if (id != null) { // 排除自己这个活动
  119 + discountActivityProductList.removeIf(product -> id.equals(product.getActivityId()));
  120 + }
  121 + // 如果非空,则说明冲突
  122 + if (CollUtil.isNotEmpty(discountActivityProductList)) {
  123 + throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS);
  124 + }
  125 + }
  126 +
  127 + private List<DiscountProductDetailBO> getRewardProductListBySkuIds(Collection<Long> skuIds,
  128 + Collection<Integer> statuses) {
  129 + // 查询商品
  130 + List<DiscountProductDO> products = discountProductMapper.selectListBySkuId(skuIds);
  131 + if (CollUtil.isEmpty(products)) {
  132 + return new ArrayList<>(0);
  133 + }
  134 +
  135 + // 查询活动
  136 + List<DiscountActivityDO> activities = discountActivityMapper.selectBatchIds(skuIds);
  137 + activities.removeIf(activity -> !statuses.contains(activity.getStatus())); // 移除不满足 statuses 状态的
  138 + Map<Long, DiscountActivityDO> activityMap = CollectionUtils.convertMap(activities, DiscountActivityDO::getId);
  139 +
  140 + // 移除不满足活动的商品
  141 + products.removeIf(product -> !activityMap.containsKey(product.getActivityId()));
  142 + return DiscountActivityConvert.INSTANCE.convertList(products, activityMap);
  143 + }
  144 +
  145 + @Override
  146 + public void closeRewardActivity(Long id) {
  147 + // 校验存在
  148 + DiscountActivityDO dbDiscountActivity = validateDiscountActivityExists(id);
  149 + if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能关闭噢
  150 + throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
  151 + }
  152 + if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动,不能关闭噢
  153 + throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END);
  154 + }
  155 +
  156 + // 更新
  157 + DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
  158 + discountActivityMapper.updateById(updateObj);
  159 + }
  160 +
  161 + @Override
  162 + public void deleteDiscountActivity(Long id) {
  163 + // 校验存在
  164 + DiscountActivityDO discountActivity = validateDiscountActivityExists(id);
  165 + if (!discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动,不能删除噢
  166 + throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
  167 + }
  168 +
  169 + // 删除
  170 + discountActivityMapper.deleteById(id);
  171 + }
  172 +
  173 + private DiscountActivityDO validateDiscountActivityExists(Long id) {
  174 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(id);
  175 + if (discountActivity == null) {
  176 + throw exception(DISCOUNT_ACTIVITY_NOT_EXISTS);
  177 + }
  178 + return discountActivity;
  179 + }
  180 +
  181 + @Override
  182 + public DiscountActivityDO getDiscountActivity(Long id) {
  183 + return discountActivityMapper.selectById(id);
  184 + }
  185 +
  186 + @Override
  187 + public PageResult<DiscountActivityDO> getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO) {
  188 + return discountActivityMapper.selectPage(pageReqVO);
  189 + }
  190 +
  191 + @Override
  192 + public List<DiscountProductDO> getDiscountProductsByActivityId(Long activityId) {
  193 + return discountProductMapper.selectListByActivityId(activityId);
  194 + }
  195 +
  196 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountService.java deleted
1 -package cn.iocoder.yudao.module.promotion.service.discount;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;  
4 -  
5 -import java.util.Collection;  
6 -import java.util.Map;  
7 -  
8 -/**  
9 - * 限时折扣 Service 接口  
10 - *  
11 - * @author 芋道源码  
12 - */  
13 -public interface DiscountService {  
14 -  
15 - /**  
16 - * 基于指定 SKU 编号数组,获得匹配的限时折扣商品  
17 - *  
18 - * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态  
19 - *  
20 - * @param skuIds SKU 编号数组  
21 - * @return 匹配的限时折扣商品  
22 - */  
23 - Map<Long, DiscountProductDO> getMatchDiscountProducts(Collection<Long> skuIds);  
24 -  
25 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountServiceImpl.java deleted
1 -package cn.iocoder.yudao.module.promotion.service.discount;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;  
4 -import org.springframework.stereotype.Service;  
5 -import org.springframework.validation.annotation.Validated;  
6 -  
7 -import java.util.Collection;  
8 -import java.util.HashMap;  
9 -import java.util.Map;  
10 -  
11 -/**  
12 - * 限时折扣 Service 实现类  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Service  
17 -@Validated  
18 -public class DiscountServiceImpl implements DiscountService {  
19 -  
20 - // TODO 芋艿:待实现  
21 - @Override  
22 - public Map<Long, DiscountProductDO> getMatchDiscountProducts(Collection<Long> skuIds) {  
23 - Map<Long, DiscountProductDO> products = new HashMap<>();  
24 - products.put(1L, new DiscountProductDO().setPromotionPrice(100));  
25 - products.put(2L, new DiscountProductDO().setPromotionPrice(50));  
26 - return products;  
27 - }  
28 -  
29 -}  
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserInfoDTO.java renamed to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/bo/DiscountProductDetailBO.java
1 -package cn.iocoder.yudao.module.member.api.user.dto; 1 +package cn.iocoder.yudao.module.promotion.service.discount.bo;
2 2
3 -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;  
4 import lombok.Data; 3 import lombok.Data;
5 4
6 -import java.util.Date;  
7 -  
8 /** 5 /**
9 - * 用户信息 Response DTO 6 + * 限时折扣活动商品 BO
10 * 7 *
11 * @author 芋道源码 8 * @author 芋道源码
12 */ 9 */
13 @Data 10 @Data
14 -public class UserInfoDTO { 11 +public class DiscountProductDetailBO {
  12 +
  13 + // ========== DiscountProductDO 字段 ==========
15 14
16 /** 15 /**
17 - * 用户ID 16 + * 编号,主键自增
18 */ 17 */
19 private Long id; 18 private Long id;
20 /** 19 /**
21 - * 用户昵称 20 + * 限时折扣活动的编号
22 */ 21 */
23 - private String nickname; 22 + private Long activityId;
24 /** 23 /**
25 - * 用户头像 24 + * 商品 SPU 编号
26 */ 25 */
27 - private String avatar; 26 + private Long spuId;
28 /** 27 /**
29 - * 帐号状态  
30 - *  
31 - * 枚举 {@link CommonStatusEnum} 28 + * 商品 SKU 编号
32 */ 29 */
33 - private Integer status;  
34 - 30 + private Long skuId;
35 /** 31 /**
36 - * 手机 32 + * 折扣类型
37 */ 33 */
38 - private String mobile; 34 + private Integer discountType;
39 /** 35 /**
40 - * 注册 IP 36 + * 折扣百分比
41 */ 37 */
42 - private String registerIp; 38 + private Integer discountPercent;
43 /** 39 /**
44 - * 最后登录IP 40 + * 优惠金额,单位:分
45 */ 41 */
46 - private String loginIp; 42 + private Integer discountPrice;
  43 +
  44 + // ========== DiscountActivityDO 字段 ==========
47 /** 45 /**
48 - * 最后登录时间 46 + * 活动标题
49 */ 47 */
50 - private Date loginDate; 48 + private String activityName;
51 49
52 } 50 }
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java
@@ -4,22 +4,20 @@ import cn.hutool.core.collection.CollUtil; @@ -4,22 +4,20 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  7 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  8 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
7 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; 9 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
8 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; 10 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
9 import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert; 11 import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert;
10 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; 12 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
11 -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;  
12 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; 13 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
13 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;  
14 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum;  
15 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;  
16 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; 14 +import cn.iocoder.yudao.module.promotion.enums.common.*;
17 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; 15 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
18 -import cn.iocoder.yudao.module.promotion.service.discount.DiscountService;  
19 -import cn.iocoder.yudao.module.promotion.service.reward.RewardService;  
20 -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;  
21 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 16 +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
  17 +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO;
  18 +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
22 import com.google.common.base.Suppliers; 19 import com.google.common.base.Suppliers;
  20 +import lombok.extern.slf4j.Slf4j;
23 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
24 import org.springframework.validation.annotation.Validated; 22 import org.springframework.validation.annotation.Validated;
25 23
@@ -33,9 +31,8 @@ import java.util.function.Supplier; @@ -33,9 +31,8 @@ import java.util.function.Supplier;
33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 31 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
34 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; 32 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
35 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; 33 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
36 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_MIN_PRICE;  
37 -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_SPU;  
38 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; 34 import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
  35 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
39 import static java.util.Collections.singletonList; 36 import static java.util.Collections.singletonList;
40 37
41 /** 38 /**
@@ -54,12 +51,13 @@ import static java.util.Collections.singletonList; @@ -54,12 +51,13 @@ import static java.util.Collections.singletonList;
54 */ 51 */
55 @Service 52 @Service
56 @Validated 53 @Validated
  54 +@Slf4j
57 public class PriceServiceImpl implements PriceService { 55 public class PriceServiceImpl implements PriceService {
58 56
59 @Resource 57 @Resource
60 - private DiscountService discountService; 58 + private DiscountActivityService discountService;
61 @Resource 59 @Resource
62 - private RewardService rewardService; 60 + private RewardActivityService rewardActivityService;
63 @Resource 61 @Resource
64 private CouponService couponService; 62 private CouponService couponService;
65 63
@@ -79,7 +77,13 @@ public class PriceServiceImpl implements PriceService { @@ -79,7 +77,13 @@ public class PriceServiceImpl implements PriceService {
79 calculatePriceForOrderLevel(calculateReqDTO.getUserId(), priceCalculate); 77 calculatePriceForOrderLevel(calculateReqDTO.getUserId(), priceCalculate);
80 // 计算优惠劵级别的价格 78 // 计算优惠劵级别的价格
81 calculatePriceForCouponLevel(calculateReqDTO.getUserId(), calculateReqDTO.getCouponId(), priceCalculate); 79 calculatePriceForCouponLevel(calculateReqDTO.getUserId(), calculateReqDTO.getCouponId(), priceCalculate);
82 - // 计算【优惠劵】促销 TODO 待实现 80 +
  81 + // 如果最终支付金额小于等于 0,则抛出业务异常
  82 + if (priceCalculate.getOrder().getPayPrice() <= 0) {
  83 + log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]",
  84 + calculateReqDTO, priceCalculate);
  85 + throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL);
  86 + }
83 return priceCalculate; 87 return priceCalculate;
84 } 88 }
85 89
@@ -115,24 +119,20 @@ public class PriceServiceImpl implements PriceService { @@ -115,24 +119,20 @@ public class PriceServiceImpl implements PriceService {
115 private void calculatePriceForSkuLevel(Long userId, PriceCalculateRespDTO priceCalculate) { 119 private void calculatePriceForSkuLevel(Long userId, PriceCalculateRespDTO priceCalculate) {
116 // 获取 SKU 级别的所有优惠信息 120 // 获取 SKU 级别的所有优惠信息
117 Supplier<Double> memberDiscountPercentSupplier = getMemberDiscountPercentSupplier(userId); 121 Supplier<Double> memberDiscountPercentSupplier = getMemberDiscountPercentSupplier(userId);
118 - Map<Long, DiscountProductDO> discountProducts = discountService.getMatchDiscountProducts( 122 + Map<Long, DiscountProductDetailBO> discountProducts = discountService.getMatchDiscountProducts(
119 convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSkuId)); 123 convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSkuId));
120 124
121 // 处理每个 SKU 的优惠 125 // 处理每个 SKU 的优惠
122 priceCalculate.getOrder().getItems().forEach(orderItem -> { 126 priceCalculate.getOrder().getItems().forEach(orderItem -> {
123 // 获取该 SKU 的优惠信息 127 // 获取该 SKU 的优惠信息
124 Double memberDiscountPercent = memberDiscountPercentSupplier.get(); 128 Double memberDiscountPercent = memberDiscountPercentSupplier.get();
125 - DiscountProductDO discountProduct = discountProducts.get(orderItem.getSkuId());  
126 - if (discountProduct != null // 假设优惠价格更贵,则认为没优惠  
127 - && discountProduct.getPromotionPrice() >= orderItem.getOriginalUnitPrice()) {  
128 - discountProduct = null;  
129 - } 129 + DiscountProductDetailBO discountProduct = discountProducts.get(orderItem.getSkuId());
130 if (memberDiscountPercent == null && discountProduct == null) { 130 if (memberDiscountPercent == null && discountProduct == null) {
131 return; 131 return;
132 } 132 }
133 // 计算价格,判断选择哪个折扣 133 // 计算价格,判断选择哪个折扣
134 Integer memberPrice = memberDiscountPercent != null ? (int) (orderItem.getPayPrice() * memberDiscountPercent / 100) : null; 134 Integer memberPrice = memberDiscountPercent != null ? (int) (orderItem.getPayPrice() * memberDiscountPercent / 100) : null;
135 - Integer promotionPrice = discountProduct != null ? discountProduct.getPromotionPrice() * orderItem.getCount() : null; 135 + Integer promotionPrice = discountProduct != null ? getDiscountProductPrice(discountProduct, orderItem) : null;
136 if (memberPrice == null) { 136 if (memberPrice == null) {
137 calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice); 137 calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice);
138 } else if (promotionPrice == null) { 138 } else if (promotionPrice == null) {
@@ -145,6 +145,19 @@ public class PriceServiceImpl implements PriceService { @@ -145,6 +145,19 @@ public class PriceServiceImpl implements PriceService {
145 }); 145 });
146 } 146 }
147 147
  148 + private Integer getDiscountProductPrice(DiscountProductDetailBO discountProduct,
  149 + PriceCalculateRespDTO.OrderItem orderItem) {
  150 + Integer price = orderItem.getPayPrice();
  151 + if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价
  152 + price -= discountProduct.getDiscountPrice() * orderItem.getCount();
  153 + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折
  154 + price = price * discountProduct.getDiscountPercent() / 100;
  155 + } else {
  156 + throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct));
  157 + }
  158 + return price;
  159 + }
  160 +
148 private void calculatePriceByMemberDiscount(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, 161 private void calculatePriceByMemberDiscount(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem,
149 Integer memberPrice) { 162 Integer memberPrice) {
150 // 记录优惠明细 163 // 记录优惠明细
@@ -156,7 +169,7 @@ public class PriceServiceImpl implements PriceService { @@ -156,7 +169,7 @@ public class PriceServiceImpl implements PriceService {
156 } 169 }
157 170
158 private void calculatePriceByDiscountActivity(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, 171 private void calculatePriceByDiscountActivity(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem,
159 - DiscountProductDO discountProduct, Integer promotionPrice) { 172 + DiscountProductDetailBO discountProduct, Integer promotionPrice) {
160 // 记录优惠明细 173 // 记录优惠明细
161 addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(), 174 addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(),
162 PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), PromotionLevelEnum.SKU.getLevel(), promotionPrice, 175 PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), PromotionLevelEnum.SKU.getLevel(), promotionPrice,
@@ -191,7 +204,7 @@ public class PriceServiceImpl implements PriceService { @@ -191,7 +204,7 @@ public class PriceServiceImpl implements PriceService {
191 private void calculatePriceForOrderLevel(Long userId, PriceCalculateRespDTO priceCalculate) { 204 private void calculatePriceForOrderLevel(Long userId, PriceCalculateRespDTO priceCalculate) {
192 // 获取 SKU 级别的所有优惠信息 205 // 获取 SKU 级别的所有优惠信息
193 Set<Long> spuIds = convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSpuId); 206 Set<Long> spuIds = convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSpuId);
194 - Map<RewardActivityDO, Set<Long>> rewardActivities = rewardService.getMatchRewardActivities(spuIds); 207 + Map<RewardActivityDO, Set<Long>> rewardActivities = rewardActivityService.getMatchRewardActivities(spuIds);
195 208
196 // 处理满减送活动 209 // 处理满减送活动
197 if (CollUtil.isNotEmpty(rewardActivities)) { 210 if (CollUtil.isNotEmpty(rewardActivities)) {
@@ -216,7 +229,6 @@ public class PriceServiceImpl implements PriceService { @@ -216,7 +229,6 @@ public class PriceServiceImpl implements PriceService {
216 } 229 }
217 230
218 // 分摊金额 231 // 分摊金额
219 - // TODO 芋艿:limit 不能超过最大价格  
220 List<Integer> discountPartPrices = dividePrice(orderItems, rule.getDiscountPrice()); 232 List<Integer> discountPartPrices = dividePrice(orderItems, rule.getDiscountPrice());
221 // 记录优惠明细 233 // 记录优惠明细
222 addPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(), 234 addPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(),
@@ -283,7 +295,7 @@ public class PriceServiceImpl implements PriceService { @@ -283,7 +295,7 @@ public class PriceServiceImpl implements PriceService {
283 // 计算是否满足优惠劵的使用金额 295 // 计算是否满足优惠劵的使用金额
284 Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); 296 Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
285 assert originPrice != null; 297 assert originPrice != null;
286 - if (originPrice < coupon.getPriceAvailable()) { 298 + if (originPrice < coupon.getUsePrice()) {
287 throw exception(COUPON_NO_MATCH_MIN_PRICE); 299 throw exception(COUPON_NO_MATCH_MIN_PRICE);
288 } 300 }
289 301
@@ -291,10 +303,9 @@ public class PriceServiceImpl implements PriceService { @@ -291,10 +303,9 @@ public class PriceServiceImpl implements PriceService {
291 priceCalculate.getOrder().setCouponId(couponId); 303 priceCalculate.getOrder().setCouponId(couponId);
292 Integer couponPrice = getCouponPrice(coupon, originPrice); 304 Integer couponPrice = getCouponPrice(coupon, originPrice);
293 // 分摊金额 305 // 分摊金额
294 - // TODO 芋艿:limit 不能超过最大价格  
295 List<Integer> couponPartPrices = dividePrice(orderItems, couponPrice); 306 List<Integer> couponPartPrices = dividePrice(orderItems, couponPrice);
296 // 记录优惠明细 307 // 记录优惠明细
297 - addPromotion(priceCalculate, orderItems, coupon.getId(), coupon.getTitle(), 308 + addPromotion(priceCalculate, orderItems, coupon.getId(), coupon.getName(),
298 PromotionTypeEnum.COUPON.getType(), PromotionLevelEnum.COUPON.getLevel(), couponPartPrices, 309 PromotionTypeEnum.COUPON.getType(), PromotionLevelEnum.COUPON.getLevel(), couponPartPrices,
299 true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice))); 310 true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice)));
300 // 修改 SKU 的分摊 311 // 修改 SKU 的分摊
@@ -309,19 +320,18 @@ public class PriceServiceImpl implements PriceService { @@ -309,19 +320,18 @@ public class PriceServiceImpl implements PriceService {
309 return priceCalculate.getOrder().getItems(); 320 return priceCalculate.getOrder().getItems();
310 } 321 }
311 return CollectionUtils.filterList(priceCalculate.getOrder().getItems(), 322 return CollectionUtils.filterList(priceCalculate.getOrder().getItems(),
312 - orderItem -> coupon.getSpuIds().contains(orderItem.getSpuId())); 323 + orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId()));
313 } 324 }
314 325
315 private Integer getCouponPrice(CouponDO coupon, Integer originPrice) { 326 private Integer getCouponPrice(CouponDO coupon, Integer originPrice) {
316 - // TODO 芋艿 getPreferentialType 的枚举判断  
317 - if (coupon.getPreferentialType().equals(1)) { // 减价  
318 - return coupon.getPriceOff();  
319 - } else if (coupon.getPreferentialType().equals(2)) { // 打折  
320 - Integer couponPrice = originPrice * coupon.getPercentOff() / 100;  
321 - return coupon.getDiscountPriceLimit() == null ? couponPrice  
322 - : Math.min(couponPrice, coupon.getDiscountPriceLimit()); // 优惠上限 327 + if (PromotionDiscountTypeEnum.PRICE.getType().equals(coupon.getDiscountType())) { // 减价
  328 + return coupon.getDiscountPrice();
  329 + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(coupon.getDiscountType())) { // 打折
  330 + int couponPrice = originPrice * coupon.getDiscountPercent() / 100;
  331 + return coupon.getDiscountLimitPrice() == null ? couponPrice
  332 + : Math.min(couponPrice, coupon.getDiscountLimitPrice()); // 优惠上限
323 } 333 }
324 - throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon.toString())); 334 + throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon));
325 } 335 }
326 336
327 // ========== 其它相对通用的方法 ========== 337 // ========== 其它相对通用的方法 ==========
@@ -410,13 +420,16 @@ public class PriceServiceImpl implements PriceService { @@ -410,13 +420,16 @@ public class PriceServiceImpl implements PriceService {
410 */ 420 */
411 private void modifyOrderItemPayPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer newPayPrice, 421 private void modifyOrderItemPayPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer newPayPrice,
412 PriceCalculateRespDTO priceCalculate) { 422 PriceCalculateRespDTO priceCalculate) {
  423 + // diffPayPrice 等于额外增加的商品级的优惠
413 int diffPayPrice = orderItem.getPayPrice() - newPayPrice; 424 int diffPayPrice = orderItem.getPayPrice() - newPayPrice;
414 // 设置 OrderItem 价格相关字段 425 // 设置 OrderItem 价格相关字段
415 orderItem.setDiscountPrice(orderItem.getDiscountPrice() + diffPayPrice); 426 orderItem.setDiscountPrice(orderItem.getDiscountPrice() + diffPayPrice);
416 orderItem.setPayPrice(newPayPrice); 427 orderItem.setPayPrice(newPayPrice);
417 orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice()); 428 orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice());
418 // 设置 Order 相关相关字段 429 // 设置 Order 相关相关字段
419 - priceCalculate.getOrder().setPayPrice(priceCalculate.getOrder().getPayPrice() - diffPayPrice); 430 + PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
  431 + order.setPayPrice(order.getPayPrice() - diffPayPrice);
  432 + order.setOrderPrice(order.getOrderPrice() - diffPayPrice);
420 } 433 }
421 434
422 /** 435 /**
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.service.reward;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
  8 +
  9 +import javax.validation.Valid;
  10 +import java.util.Map;
  11 +import java.util.Set;
  12 +
  13 +/**
  14 + * 满减送活动 Service 接口
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +public interface RewardActivityService {
  19 +
  20 + /**
  21 + * 创建满减送活动
  22 + *
  23 + * @param createReqVO 创建信息
  24 + * @return 编号
  25 + */
  26 + Long createRewardActivity(@Valid RewardActivityCreateReqVO createReqVO);
  27 +
  28 + /**
  29 + * 更新满减送活动
  30 + *
  31 + * @param updateReqVO 更新信息
  32 + */
  33 + void updateRewardActivity(@Valid RewardActivityUpdateReqVO updateReqVO);
  34 +
  35 + /**
  36 + * 关闭满减送活动
  37 + *
  38 + * @param id 活动编号
  39 + */
  40 + void closeRewardActivity(Long id);
  41 +
  42 + /**
  43 + * 删除满减送活动
  44 + *
  45 + * @param id 编号
  46 + */
  47 + void deleteRewardActivity(Long id);
  48 +
  49 + /**
  50 + * 获得满减送活动
  51 + *
  52 + * @param id 编号
  53 + * @return 满减送活动
  54 + */
  55 + RewardActivityDO getRewardActivity(Long id);
  56 +
  57 + /**
  58 + * 获得满减送活动分页
  59 + *
  60 + * @param pageReqVO 分页查询
  61 + * @return 满减送活动分页
  62 + */
  63 + PageResult<RewardActivityDO> getRewardActivityPage(RewardActivityPageReqVO pageReqVO);
  64 +
  65 + /**
  66 + * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动
  67 + *
  68 + * @param spuIds SPU 编号数组
  69 + * @return 满减送活动,与对应的 SPU 编号的映射。即,value 就是 SPU 编号的集合
  70 + */
  71 + Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds);
  72 +
  73 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.service.reward;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
  9 +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert;
  10 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
  11 +import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
  12 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  13 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
  14 +import cn.iocoder.yudao.module.promotion.util.PromotionUtils;
  15 +import org.springframework.stereotype.Service;
  16 +import org.springframework.validation.annotation.Validated;
  17 +
  18 +import javax.annotation.Resource;
  19 +import java.util.Collection;
  20 +import java.util.List;
  21 +import java.util.Map;
  22 +import java.util.Set;
  23 +
  24 +import static cn.hutool.core.collection.CollUtil.intersectionDistinct;
  25 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  26 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  27 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
  28 +import static java.util.Arrays.asList;
  29 +import static java.util.Collections.singleton;
  30 +
  31 +/**
  32 + * 满减送活动 Service 实现类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Service
  37 +@Validated
  38 +public class RewardActivityServiceImpl implements RewardActivityService {
  39 +
  40 + @Resource
  41 + private RewardActivityMapper rewardActivityMapper;
  42 +
  43 + @Override
  44 + public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) {
  45 + // 校验商品是否冲突
  46 + validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds());
  47 +
  48 + // 插入
  49 + RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO)
  50 + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime()));
  51 + rewardActivityMapper.insert(rewardActivity);
  52 + // 返回
  53 + return rewardActivity.getId();
  54 + }
  55 +
  56 + @Override
  57 + public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) {
  58 + // 校验存在
  59 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId());
  60 + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢
  61 + throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
  62 + }
  63 + // 校验商品是否冲突
  64 + validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
  65 +
  66 + // 更新
  67 + RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO)
  68 + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime()));
  69 + rewardActivityMapper.updateById(updateObj);
  70 + }
  71 +
  72 + @Override
  73 + public void closeRewardActivity(Long id) {
  74 + // 校验存在
  75 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(id);
  76 + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能关闭噢
  77 + throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED);
  78 + }
  79 + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动,不能关闭噢
  80 + throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END);
  81 + }
  82 +
  83 + // 更新
  84 + RewardActivityDO updateObj = new RewardActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
  85 + rewardActivityMapper.updateById(updateObj);
  86 + }
  87 +
  88 + @Override
  89 + public void deleteRewardActivity(Long id) {
  90 + // 校验存在
  91 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(id);
  92 + if (!dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动,不能删除噢
  93 + throw exception(REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED);
  94 + }
  95 +
  96 + // 删除
  97 + rewardActivityMapper.deleteById(id);
  98 + }
  99 +
  100 + private RewardActivityDO validateRewardActivityExists(Long id) {
  101 + RewardActivityDO activity = rewardActivityMapper.selectById(id);
  102 + if (activity == null) {
  103 + throw exception(REWARD_ACTIVITY_NOT_EXISTS);
  104 + }
  105 + return activity;
  106 + }
  107 +
  108 + /**
  109 + * 校验商品参加的活动是否冲突
  110 + *
  111 + * @param id 活动编号
  112 + * @param spuIds 商品 SPU 编号数组
  113 + */
  114 + private void validateRewardActivitySpuConflicts(Long id, Collection<Long> spuIds) {
  115 + if (CollUtil.isEmpty(spuIds)) {
  116 + return;
  117 + }
  118 + // 查询商品参加的活动
  119 + List<RewardActivityDO> rewardActivityList = getRewardActivityListBySpuIds(spuIds,
  120 + asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus()));
  121 + if (id != null) { // 排除自己这个活动
  122 + rewardActivityList.removeIf(activity -> id.equals(activity.getId()));
  123 + }
  124 + // 如果非空,则说明冲突
  125 + if (CollUtil.isNotEmpty(rewardActivityList)) {
  126 + throw exception(REWARD_ACTIVITY_SPU_CONFLICTS);
  127 + }
  128 + }
  129 +
  130 + /**
  131 + * 获得商品参加的满减送活动的数组
  132 + *
  133 + * @param spuIds 商品 SPU 编号数组
  134 + * @param statuses 活动状态数组
  135 + * @return 商品参加的满减送活动的数组
  136 + */
  137 + private List<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds,
  138 + Collection<Integer> statuses) {
  139 + List<RewardActivityDO> list = rewardActivityMapper.selectListByStatus(statuses);
  140 + return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds));
  141 + }
  142 +
  143 + @Override
  144 + public RewardActivityDO getRewardActivity(Long id) {
  145 + return rewardActivityMapper.selectById(id);
  146 + }
  147 +
  148 + @Override
  149 + public PageResult<RewardActivityDO> getRewardActivityPage(RewardActivityPageReqVO pageReqVO) {
  150 + return rewardActivityMapper.selectPage(pageReqVO);
  151 + }
  152 +
  153 + @Override
  154 + public Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds) {
  155 + // 如果有全局活动,则直接选择它
  156 + List<RewardActivityDO> allActivities = rewardActivityMapper.selectListByProductScopeAndStatus(
  157 + PromotionProductScopeEnum.ALL.getScope(), PromotionActivityStatusEnum.RUN.getStatus());
  158 + if (CollUtil.isNotEmpty(allActivities)) {
  159 + return MapUtil.builder(allActivities.get(0), spuIds).build();
  160 + }
  161 +
  162 + // 查询某个活动参加的活动
  163 + List<RewardActivityDO> productActivityList = getRewardActivityListBySpuIds(spuIds,
  164 + singleton(PromotionActivityStatusEnum.RUN.getStatus()));
  165 + return convertMap(productActivityList, activity -> activity,
  166 + rewardActivityDO -> intersectionDistinct(rewardActivityDO.getProductSpuIds(), spuIds)); // 求交集返回
  167 + }
  168 +
  169 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardService.java deleted
1 -package cn.iocoder.yudao.module.promotion.service.reward;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;  
4 -  
5 -import java.util.Map;  
6 -import java.util.Set;  
7 -  
8 -/**  
9 - * 满减送 Service 接口  
10 - *  
11 - * @author 芋道源码  
12 - */  
13 -public interface RewardService {  
14 -  
15 - /**  
16 - * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动  
17 - *  
18 - * @param spuIds SPU 编号数组  
19 - * @return 满减送活动,与对应的 SPU 编号的映射。即,value 就是 SPU 编号的集合  
20 - */  
21 - Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds);  
22 -  
23 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardServiceImpl.java deleted
1 -package cn.iocoder.yudao.module.promotion.service.reward;  
2 -  
3 -import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;  
4 -import org.springframework.stereotype.Service;  
5 -import org.springframework.validation.annotation.Validated;  
6 -  
7 -import java.util.Collections;  
8 -import java.util.Map;  
9 -import java.util.Set;  
10 -  
11 -/**  
12 - * 满减送 Service 实现类  
13 - *  
14 - * @author 芋道源码  
15 - */  
16 -@Service  
17 -@Validated  
18 -public class RewardServiceImpl implements RewardService {  
19 -  
20 - // TODO 芋艿:待实现  
21 - @Override  
22 - public Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds) {  
23 - return Collections.emptyMap();  
24 - }  
25 -  
26 -}  
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.promotion.util;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
  4 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  5 +
  6 +import java.util.Date;
  7 +
  8 +/**
  9 + * 活动工具类
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +public class PromotionUtils {
  14 +
  15 + /**
  16 + * 根据时间,计算活动状态
  17 + *
  18 + * @param startTime 开始时间
  19 + * @param endTime 结束时间
  20 + * @return 活动状态
  21 + */
  22 + public static Integer calculateActivityStatus(Date startTime, Date endTime) {
  23 + if (DateUtils.beforeNow(endTime)) {
  24 + return PromotionActivityStatusEnum.END.getStatus();
  25 + }
  26 + if (DateUtils.afterNow(startTime)) {
  27 + return PromotionActivityStatusEnum.WAIT.getStatus();
  28 + }
  29 + return PromotionActivityStatusEnum.RUN.getStatus();
  30 + }
  31 +
  32 +}
yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/coupon/CouponTemplateMapper.xml 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper">
  4 +
  5 + <update id="updateTakeCount">
  6 + UPDATE promotion_coupon_template
  7 + SET take_count = take_count + #{incrCount}
  8 + WHERE id = #{id}
  9 + </update>
  10 +
  11 +</mapper>
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java
1 package cn.iocoder.yudao.module.promotion.service.coupon; 1 package cn.iocoder.yudao.module.promotion.service.coupon;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 5 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO;  
6 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO;  
7 -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 6 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO;
8 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
9 import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; 10 import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper;
10 -import org.junit.jupiter.api.Disabled; 11 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
  12 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
  13 +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
11 import org.junit.jupiter.api.Test; 14 import org.junit.jupiter.api.Test;
12 import org.springframework.context.annotation.Import; 15 import org.springframework.context.annotation.Import;
13 16
14 import javax.annotation.Resource; 17 import javax.annotation.Resource;
15 import java.util.Date; 18 import java.util.Date;
16 19
  20 +import static cn.hutool.core.util.RandomUtil.randomEle;
  21 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
17 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; 22 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
18 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 23 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
19 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; 24 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
@@ -39,7 +44,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest { @@ -39,7 +44,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest {
39 @Test 44 @Test
40 public void testCreateCouponTemplate_success() { 45 public void testCreateCouponTemplate_success() {
41 // 准备参数 46 // 准备参数
42 - CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class); 47 + CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class,
  48 + o -> o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope())
  49 + .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType())
  50 + .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType()));
43 51
44 // 调用 52 // 调用
45 Long couponTemplateId = couponTemplateService.createCouponTemplate(reqVO); 53 Long couponTemplateId = couponTemplateService.createCouponTemplate(reqVO);
@@ -58,6 +66,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest { @@ -58,6 +66,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest {
58 // 准备参数 66 // 准备参数
59 CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> { 67 CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> {
60 o.setId(dbCouponTemplate.getId()); // 设置更新的 ID 68 o.setId(dbCouponTemplate.getId()); // 设置更新的 ID
  69 + // 其它通用字段
  70 + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope())
  71 + .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType())
  72 + .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType());
61 }); 73 });
62 74
63 // 调用 75 // 调用
@@ -100,30 +112,29 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest { @@ -100,30 +112,29 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest {
100 } 112 }
101 113
102 @Test 114 @Test
103 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
104 public void testGetCouponTemplatePage() { 115 public void testGetCouponTemplatePage() {
105 // mock 数据 116 // mock 数据
106 CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class, o -> { // 等会查询到 117 CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class, o -> { // 等会查询到
107 - o.setName(null);  
108 - o.setStatus(null);  
109 - o.setDiscountType(null);  
110 - o.setCreateTime(null); 118 + o.setName("芋艿");
  119 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  120 + o.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType());
  121 + o.setCreateTime(buildTime(2022, 2, 2));
111 }); 122 });
112 couponTemplateMapper.insert(dbCouponTemplate); 123 couponTemplateMapper.insert(dbCouponTemplate);
113 // 测试 name 不匹配 124 // 测试 name 不匹配
114 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setName(null))); 125 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setName("土豆")));
115 // 测试 status 不匹配 126 // 测试 status 不匹配
116 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setStatus(null))); 127 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
117 // 测试 type 不匹配 128 // 测试 type 不匹配
118 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setDiscountType(null))); 129 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType())));
119 // 测试 createTime 不匹配 130 // 测试 createTime 不匹配
120 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setCreateTime(null))); 131 + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setCreateTime(buildTime(2022, 1, 1))));
121 // 准备参数 132 // 准备参数
122 CouponTemplatePageReqVO reqVO = new CouponTemplatePageReqVO(); 133 CouponTemplatePageReqVO reqVO = new CouponTemplatePageReqVO();
123 - reqVO.setName(null);  
124 - reqVO.setStatus(null);  
125 - reqVO.setDiscountType(null);  
126 - reqVO.setCreateTime((new Date[]{})); 134 + reqVO.setName("芋艿");
  135 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  136 + reqVO.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType());
  137 + reqVO.setCreateTime((new Date[]{buildTime(2022, 2, 1), buildTime(2022, 2, 3)}));
127 138
128 // 调用 139 // 调用
129 PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage(reqVO); 140 PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage(reqVO);
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.service.discount;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
  8 +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO;
  9 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO;
  10 +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;
  11 +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper;
  12 +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper;
  13 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  14 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum;
  15 +import org.junit.jupiter.api.Test;
  16 +import org.springframework.context.annotation.Import;
  17 +
  18 +import javax.annotation.Resource;
  19 +import java.time.Duration;
  20 +import java.util.Date;
  21 +import java.util.List;
  22 +
  23 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
  24 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
  25 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  26 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  27 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  28 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  29 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  30 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DISCOUNT_ACTIVITY_NOT_EXISTS;
  31 +import static java.util.Arrays.asList;
  32 +import static org.junit.jupiter.api.Assertions.*;
  33 +
  34 +/**
  35 +* {@link DiscountActivityServiceImpl} 的单元测试类
  36 +*
  37 +* @author 芋道源码
  38 +*/
  39 +@Import(DiscountActivityServiceImpl.class)
  40 +public class DiscountActivityServiceImplTest extends BaseDbUnitTest {
  41 +
  42 + @Resource
  43 + private DiscountActivityServiceImpl discountActivityService;
  44 +
  45 + @Resource
  46 + private DiscountActivityMapper discountActivityMapper;
  47 + @Resource
  48 + private DiscountProductMapper discountProductMapper;
  49 +
  50 + @Test
  51 + public void testCreateDiscountActivity_success() {
  52 + // 准备参数
  53 + DiscountActivityCreateReqVO reqVO = randomPojo(DiscountActivityCreateReqVO.class, o -> {
  54 + // 用于触发进行中的状态
  55 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2)));
  56 + // 设置商品
  57 + o.setProducts(asList(new DiscountActivityBaseVO.Product().setSpuId(1L).setSkuId(2L)
  58 + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3),
  59 + new DiscountActivityBaseVO.Product().setSpuId(10L).setSkuId(20L)
  60 + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30)));
  61 + });
  62 +
  63 + // 调用
  64 + Long discountActivityId = discountActivityService.createDiscountActivity(reqVO);
  65 + // 断言
  66 + assertNotNull(discountActivityId);
  67 + // 校验活动
  68 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(discountActivityId);
  69 + assertPojoEquals(reqVO, discountActivity);
  70 + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus());
  71 + // 校验商品
  72 + List<DiscountProductDO> discountProducts = discountProductMapper.selectList(DiscountProductDO::getActivityId, discountActivity.getId());
  73 + assertEquals(discountProducts.size(), reqVO.getProducts().size());
  74 + for (int i = 0; i < reqVO.getProducts().size(); i++) {
  75 + DiscountActivityBaseVO.Product product = reqVO.getProducts().get(i);
  76 + DiscountProductDO discountProduct = discountProducts.get(i);
  77 + assertEquals(discountProduct.getActivityId(), discountActivity.getId());
  78 + assertEquals(discountProduct.getSpuId(), product.getSpuId());
  79 + assertEquals(discountProduct.getSkuId(), product.getSkuId());
  80 + assertEquals(discountProduct.getDiscountType(), product.getDiscountType());
  81 + assertEquals(discountProduct.getDiscountPrice(), product.getDiscountPrice());
  82 + assertEquals(discountProduct.getDiscountPercent(), product.getDiscountPercent());
  83 + }
  84 + }
  85 +
  86 + @Test
  87 + public void testUpdateDiscountActivity_success() {
  88 + // mock 数据(商品)
  89 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class);
  90 + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据
  91 + // mock 数据(活动)
  92 + DiscountProductDO dbDiscountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(dbDiscountActivity.getId())
  93 + .setSpuId(1L).setSkuId(2L).setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3).setDiscountPercent(null));
  94 + DiscountProductDO dbDiscountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(dbDiscountActivity.getId())
  95 + .setSpuId(10L).setSkuId(20L).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30).setDiscountPrice(null));
  96 + discountProductMapper.insert(dbDiscountProduct01);
  97 + discountProductMapper.insert(dbDiscountProduct02);
  98 + // 准备参数
  99 + DiscountActivityUpdateReqVO reqVO = randomPojo(DiscountActivityUpdateReqVO.class, o -> {
  100 + o.setId(dbDiscountActivity.getId()); // 设置更新的 ID
  101 + // 用于触发进行中的状态
  102 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2)));
  103 + // 设置商品
  104 + o.setProducts(asList(new DiscountActivityBaseVO.Product().setSpuId(1L).setSkuId(2L)
  105 + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3).setDiscountPercent(null),
  106 + new DiscountActivityBaseVO.Product().setSpuId(100L).setSkuId(200L)
  107 + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30).setDiscountPrice(null)));
  108 + });
  109 +
  110 + // 调用
  111 + discountActivityService.updateDiscountActivity(reqVO);
  112 + // 校验活动
  113 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(reqVO.getId()); // 获取最新的
  114 + assertPojoEquals(reqVO, discountActivity);
  115 + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus());
  116 + // 校验商品
  117 + List<DiscountProductDO> discountProducts = discountProductMapper.selectList(DiscountProductDO::getActivityId, discountActivity.getId());
  118 + assertEquals(discountProducts.size(), reqVO.getProducts().size());
  119 + for (int i = 0; i < reqVO.getProducts().size(); i++) {
  120 + DiscountActivityBaseVO.Product product = reqVO.getProducts().get(i);
  121 + DiscountProductDO discountProduct = discountProducts.get(i);
  122 + assertEquals(discountProduct.getActivityId(), discountActivity.getId());
  123 + assertEquals(discountProduct.getSpuId(), product.getSpuId());
  124 + assertEquals(discountProduct.getSkuId(), product.getSkuId());
  125 + assertEquals(discountProduct.getDiscountType(), product.getDiscountType());
  126 + assertEquals(discountProduct.getDiscountPrice(), product.getDiscountPrice());
  127 + assertEquals(discountProduct.getDiscountPercent(), product.getDiscountPercent());
  128 + }
  129 + }
  130 +
  131 + @Test
  132 + public void testCloseDiscountActivity() {
  133 + // mock 数据
  134 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class,
  135 + o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus()));
  136 + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据
  137 + // 准备参数
  138 + Long id = dbDiscountActivity.getId();
  139 +
  140 + // 调用
  141 + discountActivityService.closeRewardActivity(id);
  142 + // 校验状态
  143 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(id);
  144 + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus());
  145 + }
  146 +
  147 + @Test
  148 + public void testUpdateDiscountActivity_notExists() {
  149 + // 准备参数
  150 + DiscountActivityUpdateReqVO reqVO = randomPojo(DiscountActivityUpdateReqVO.class);
  151 +
  152 + // 调用, 并断言异常
  153 + assertServiceException(() -> discountActivityService.updateDiscountActivity(reqVO), DISCOUNT_ACTIVITY_NOT_EXISTS);
  154 + }
  155 +
  156 + @Test
  157 + public void testDeleteDiscountActivity_success() {
  158 + // mock 数据
  159 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class,
  160 + o -> o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()));
  161 + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据
  162 + // 准备参数
  163 + Long id = dbDiscountActivity.getId();
  164 +
  165 + // 调用
  166 + discountActivityService.deleteDiscountActivity(id);
  167 + // 校验数据不存在了
  168 + assertNull(discountActivityMapper.selectById(id));
  169 + }
  170 +
  171 + @Test
  172 + public void testDeleteDiscountActivity_notExists() {
  173 + // 准备参数
  174 + Long id = randomLongId();
  175 +
  176 + // 调用, 并断言异常
  177 + assertServiceException(() -> discountActivityService.deleteDiscountActivity(id), DISCOUNT_ACTIVITY_NOT_EXISTS);
  178 + }
  179 +
  180 + @Test
  181 + public void testGetDiscountActivityPage() {
  182 + // mock 数据
  183 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class, o -> { // 等会查询到
  184 + o.setName("芋艿");
  185 + o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus());
  186 + o.setCreateTime(buildTime(2021, 1, 15));
  187 + });
  188 + discountActivityMapper.insert(dbDiscountActivity);
  189 + // 测试 name 不匹配
  190 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setName("土豆")));
  191 + // 测试 status 不匹配
  192 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setStatus(PromotionActivityStatusEnum.END.getStatus())));
  193 + // 测试 createTime 不匹配
  194 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setCreateTime(buildTime(2021, 2, 10))));
  195 + // 准备参数
  196 + DiscountActivityPageReqVO reqVO = new DiscountActivityPageReqVO();
  197 + reqVO.setName("芋艿");
  198 + reqVO.setStatus(PromotionActivityStatusEnum.WAIT.getStatus());
  199 + reqVO.setCreateTime((new Date[]{buildTime(2021, 1, 1), buildTime(2021, 1, 31)}));
  200 +
  201 + // 调用
  202 + PageResult<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(reqVO);
  203 + // 断言
  204 + assertEquals(1, pageResult.getTotal());
  205 + assertEquals(1, pageResult.getList().size());
  206 + assertPojoEquals(dbDiscountActivity, pageResult.getList().get(0));
  207 + }
  208 +
  209 +}
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java
@@ -2,20 +2,17 @@ package cn.iocoder.yudao.module.promotion.service.price; @@ -2,20 +2,17 @@ package cn.iocoder.yudao.module.promotion.service.price;
2 2
3 import cn.hutool.core.map.MapUtil; 3 import cn.hutool.core.map.MapUtil;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 4 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  5 +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
  6 +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
5 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; 7 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
6 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; 8 import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
7 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; 9 import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
8 -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO;  
9 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; 10 import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
10 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;  
11 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum;  
12 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;  
13 -import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; 11 +import cn.iocoder.yudao.module.promotion.enums.common.*;
14 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; 12 import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
15 -import cn.iocoder.yudao.module.promotion.service.discount.DiscountService;  
16 -import cn.iocoder.yudao.module.promotion.service.reward.RewardService;  
17 -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;  
18 -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; 13 +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
  14 +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO;
  15 +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
19 import org.junit.jupiter.api.Test; 16 import org.junit.jupiter.api.Test;
20 import org.mockito.InjectMocks; 17 import org.mockito.InjectMocks;
21 import org.mockito.Mock; 18 import org.mockito.Mock;
@@ -44,9 +41,9 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -44,9 +41,9 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
44 private PriceServiceImpl priceService; 41 private PriceServiceImpl priceService;
45 42
46 @Mock 43 @Mock
47 - private DiscountService discountService; 44 + private DiscountActivityService discountService;
48 @Mock 45 @Mock
49 - private RewardService rewardService; 46 + private RewardActivityService rewardActivityService;
50 @Mock 47 @Mock
51 private CouponService couponService; 48 private CouponService couponService;
52 @Mock 49 @Mock
@@ -67,6 +64,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -67,6 +64,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
67 // 断言 Order 部分 64 // 断言 Order 部分
68 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); 65 PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
69 assertEquals(order.getOriginalPrice(), 200); 66 assertEquals(order.getOriginalPrice(), 200);
  67 + assertEquals(order.getOrderPrice(), 180);
70 assertEquals(order.getDiscountPrice(), 0); 68 assertEquals(order.getDiscountPrice(), 0);
71 assertEquals(order.getPointPrice(), 0); 69 assertEquals(order.getPointPrice(), 0);
72 assertEquals(order.getDeliveryPrice(), 0); 70 assertEquals(order.getDeliveryPrice(), 0);
@@ -112,22 +110,28 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -112,22 +110,28 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
112 ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50)); 110 ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50));
113 when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02)); 111 when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02));
114 // mock 方法(限时折扣 DiscountActivity 信息) 112 // mock 方法(限时折扣 DiscountActivity 信息)
115 - DiscountProductDO discountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(1000L).setActivityName("活动 1000 号")  
116 - .setSkuId(10L).setPromotionPrice(80));  
117 - DiscountProductDO discountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(2000L).setActivityName("活动 2000 号")  
118 - .setSkuId(20L).setPromotionPrice(40)); 113 + DiscountProductDetailBO discountProduct01 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(1000L)
  114 + .setActivityName("活动 1000 号").setSkuId(10L)
  115 + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(40));
  116 + DiscountProductDetailBO discountProduct02 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(2000L)
  117 + .setActivityName("活动 2000 号").setSkuId(20L)
  118 + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(60));
119 when(discountService.getMatchDiscountProducts(eq(asSet(10L, 20L)))).thenReturn( 119 when(discountService.getMatchDiscountProducts(eq(asSet(10L, 20L)))).thenReturn(
120 MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map()); 120 MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map());
121 121
  122 + // 10L: 100 * 2 - 40 * 2 = 120
  123 + // 20L:50 * 3 - 50 * 3 * 0.4 = 90
  124 +
122 // 调用 125 // 调用
123 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); 126 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
124 // 断言 Order 部分 127 // 断言 Order 部分
125 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); 128 PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
126 assertEquals(order.getOriginalPrice(), 350); 129 assertEquals(order.getOriginalPrice(), 350);
  130 + assertEquals(order.getOrderPrice(), 210);
127 assertEquals(order.getDiscountPrice(), 0); 131 assertEquals(order.getDiscountPrice(), 0);
128 assertEquals(order.getPointPrice(), 0); 132 assertEquals(order.getPointPrice(), 0);
129 assertEquals(order.getDeliveryPrice(), 0); 133 assertEquals(order.getDeliveryPrice(), 0);
130 - assertEquals(order.getPayPrice(), 280); 134 + assertEquals(order.getPayPrice(), 210);
131 assertNull(order.getCouponId()); 135 assertNull(order.getCouponId());
132 // 断言 OrderItem 部分 136 // 断言 OrderItem 部分
133 assertEquals(order.getItems().size(), 2); 137 assertEquals(order.getItems().size(), 2);
@@ -136,19 +140,19 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -136,19 +140,19 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
136 assertEquals(orderItem01.getCount(), 2); 140 assertEquals(orderItem01.getCount(), 2);
137 assertEquals(orderItem01.getOriginalPrice(), 200); 141 assertEquals(orderItem01.getOriginalPrice(), 200);
138 assertEquals(orderItem01.getOriginalUnitPrice(), 100); 142 assertEquals(orderItem01.getOriginalUnitPrice(), 100);
139 - assertEquals(orderItem01.getDiscountPrice(), 40);  
140 - assertEquals(orderItem01.getPayPrice(), 160); 143 + assertEquals(orderItem01.getDiscountPrice(), 80);
  144 + assertEquals(orderItem01.getPayPrice(), 120);
141 assertEquals(orderItem01.getOrderPartPrice(), 0); 145 assertEquals(orderItem01.getOrderPartPrice(), 0);
142 - assertEquals(orderItem01.getOrderDividePrice(), 160); 146 + assertEquals(orderItem01.getOrderDividePrice(), 120);
143 PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1); 147 PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1);
144 assertEquals(orderItem02.getSkuId(), 20L); 148 assertEquals(orderItem02.getSkuId(), 20L);
145 assertEquals(orderItem02.getCount(), 3); 149 assertEquals(orderItem02.getCount(), 3);
146 assertEquals(orderItem02.getOriginalPrice(), 150); 150 assertEquals(orderItem02.getOriginalPrice(), 150);
147 assertEquals(orderItem02.getOriginalUnitPrice(), 50); 151 assertEquals(orderItem02.getOriginalUnitPrice(), 50);
148 - assertEquals(orderItem02.getDiscountPrice(), 30);  
149 - assertEquals(orderItem02.getPayPrice(), 120); 152 + assertEquals(orderItem02.getDiscountPrice(), 60);
  153 + assertEquals(orderItem02.getPayPrice(), 90);
150 assertEquals(orderItem02.getOrderPartPrice(), 0); 154 assertEquals(orderItem02.getOrderPartPrice(), 0);
151 - assertEquals(orderItem02.getOrderDividePrice(), 120); 155 + assertEquals(orderItem02.getOrderDividePrice(), 90);
152 // 断言 Promotion 部分 156 // 断言 Promotion 部分
153 assertEquals(priceCalculate.getPromotions().size(), 2); 157 assertEquals(priceCalculate.getPromotions().size(), 2);
154 PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0); 158 PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0);
@@ -157,28 +161,28 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -157,28 +161,28 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
157 assertEquals(promotion01.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); 161 assertEquals(promotion01.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType());
158 assertEquals(promotion01.getLevel(), PromotionLevelEnum.SKU.getLevel()); 162 assertEquals(promotion01.getLevel(), PromotionLevelEnum.SKU.getLevel());
159 assertEquals(promotion01.getOriginalPrice(), 200); 163 assertEquals(promotion01.getOriginalPrice(), 200);
160 - assertEquals(promotion01.getDiscountPrice(), 40); 164 + assertEquals(promotion01.getDiscountPrice(), 80);
161 assertTrue(promotion01.getMeet()); 165 assertTrue(promotion01.getMeet());
162 - assertEquals(promotion01.getMeetTip(), "限时折扣:省 0.40 元"); 166 + assertEquals(promotion01.getMeetTip(), "限时折扣:省 0.80 元");
163 PriceCalculateRespDTO.PromotionItem promotionItem01 = promotion01.getItems().get(0); 167 PriceCalculateRespDTO.PromotionItem promotionItem01 = promotion01.getItems().get(0);
164 assertEquals(promotion01.getItems().size(), 1); 168 assertEquals(promotion01.getItems().size(), 1);
165 assertEquals(promotionItem01.getSkuId(), 10L); 169 assertEquals(promotionItem01.getSkuId(), 10L);
166 assertEquals(promotionItem01.getOriginalPrice(), 200); 170 assertEquals(promotionItem01.getOriginalPrice(), 200);
167 - assertEquals(promotionItem01.getDiscountPrice(), 40); 171 + assertEquals(promotionItem01.getDiscountPrice(), 80);
168 PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1); 172 PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1);
169 assertEquals(promotion02.getId(), 2000L); 173 assertEquals(promotion02.getId(), 2000L);
170 assertEquals(promotion02.getName(), "活动 2000 号"); 174 assertEquals(promotion02.getName(), "活动 2000 号");
171 assertEquals(promotion02.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); 175 assertEquals(promotion02.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType());
172 assertEquals(promotion02.getLevel(), PromotionLevelEnum.SKU.getLevel()); 176 assertEquals(promotion02.getLevel(), PromotionLevelEnum.SKU.getLevel());
173 assertEquals(promotion02.getOriginalPrice(), 150); 177 assertEquals(promotion02.getOriginalPrice(), 150);
174 - assertEquals(promotion02.getDiscountPrice(), 30); 178 + assertEquals(promotion02.getDiscountPrice(), 60);
175 assertTrue(promotion02.getMeet()); 179 assertTrue(promotion02.getMeet());
176 - assertEquals(promotion02.getMeetTip(), "限时折扣:省 0.30 元"); 180 + assertEquals(promotion02.getMeetTip(), "限时折扣:省 0.60 元");
177 PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0); 181 PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0);
178 assertEquals(promotion02.getItems().size(), 1); 182 assertEquals(promotion02.getItems().size(), 1);
179 assertEquals(promotionItem02.getSkuId(), 20L); 183 assertEquals(promotionItem02.getSkuId(), 20L);
180 assertEquals(promotionItem02.getOriginalPrice(), 150); 184 assertEquals(promotionItem02.getOriginalPrice(), 150);
181 - assertEquals(promotionItem02.getDiscountPrice(), 30); 185 + assertEquals(promotionItem02.getDiscountPrice(), 60);
182 } 186 }
183 187
184 /** 188 /**
@@ -208,13 +212,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -208,13 +212,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
208 Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>(); 212 Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>();
209 matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); 213 matchRewardActivities.put(rewardActivity01, asSet(1L, 2L));
210 matchRewardActivities.put(rewardActivity02, asSet(3L)); 214 matchRewardActivities.put(rewardActivity02, asSet(3L));
211 - when(rewardService.getMatchRewardActivities(eq(asSet(1L, 2L, 3L)))).thenReturn(matchRewardActivities); 215 + when(rewardActivityService.getMatchRewardActivities(eq(asSet(1L, 2L, 3L)))).thenReturn(matchRewardActivities);
212 216
213 // 调用 217 // 调用
214 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); 218 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
215 // 断言 Order 部分 219 // 断言 Order 部分
216 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); 220 PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
217 assertEquals(order.getOriginalPrice(), 470); 221 assertEquals(order.getOriginalPrice(), 470);
  222 + assertEquals(order.getOrderPrice(), 470);
218 assertEquals(order.getDiscountPrice(), 130); 223 assertEquals(order.getDiscountPrice(), 130);
219 assertEquals(order.getPointPrice(), 0); 224 assertEquals(order.getPointPrice(), 0);
220 assertEquals(order.getDeliveryPrice(), 0); 225 assertEquals(order.getDeliveryPrice(), 0);
@@ -305,13 +310,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -305,13 +310,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
305 .setRules(singletonList(new RewardActivityDO.Rule().setLimit(351).setDiscountPrice(70)))); 310 .setRules(singletonList(new RewardActivityDO.Rule().setLimit(351).setDiscountPrice(70))));
306 Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>(); 311 Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>();
307 matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); 312 matchRewardActivities.put(rewardActivity01, asSet(1L, 2L));
308 - when(rewardService.getMatchRewardActivities(eq(asSet(1L, 2L)))).thenReturn(matchRewardActivities); 313 + when(rewardActivityService.getMatchRewardActivities(eq(asSet(1L, 2L)))).thenReturn(matchRewardActivities);
309 314
310 // 调用 315 // 调用
311 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); 316 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
312 // 断言 Order 部分 317 // 断言 Order 部分
313 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); 318 PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
314 assertEquals(order.getOriginalPrice(), 350); 319 assertEquals(order.getOriginalPrice(), 350);
  320 + assertEquals(order.getOrderPrice(), 350);
315 assertEquals(order.getDiscountPrice(), 0); 321 assertEquals(order.getDiscountPrice(), 0);
316 assertEquals(order.getPointPrice(), 0); 322 assertEquals(order.getPointPrice(), 0);
317 assertEquals(order.getDeliveryPrice(), 0); 323 assertEquals(order.getDeliveryPrice(), 0);
@@ -373,19 +379,18 @@ public class PriceServiceTest extends BaseMockitoUnitTest { @@ -373,19 +379,18 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
373 ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L)); 379 ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L));
374 when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03)); 380 when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03));
375 // mock 方法(优惠劵 Coupon 信息) 381 // mock 方法(优惠劵 Coupon 信息)
376 - CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setTitle("程序员节")  
377 - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setSpuIds(asList(1L, 2L))  
378 - .setPriceAvailable(350).setPreferentialType(2).setPercentOff(50).setDiscountPriceLimit(70)); 382 + CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setName("程序员节")
  383 + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))
  384 + .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType())
  385 + .setDiscountPercent(50).setDiscountLimitPrice(70));
379 when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon); 386 when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon);
380 387
381 - // 200 + 150; 350  
382 - //  
383 -  
384 // 调用 388 // 调用
385 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); 389 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
386 // 断言 Order 部分 390 // 断言 Order 部分
387 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); 391 PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
388 assertEquals(order.getOriginalPrice(), 470); 392 assertEquals(order.getOriginalPrice(), 470);
  393 + assertEquals(order.getOrderPrice(), 470);
389 assertEquals(order.getDiscountPrice(), 0); 394 assertEquals(order.getDiscountPrice(), 0);
390 assertEquals(order.getPointPrice(), 0); 395 assertEquals(order.getPointPrice(), 0);
391 assertEquals(order.getDeliveryPrice(), 0); 396 assertEquals(order.getDeliveryPrice(), 0);
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java 0 → 100755
  1 +package cn.iocoder.yudao.module.promotion.service.reward;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO;
  6 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO;
  7 +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO;
  8 +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
  9 +import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper;
  10 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
  11 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
  12 +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
  13 +import org.junit.jupiter.api.Test;
  14 +import org.springframework.context.annotation.Import;
  15 +
  16 +import javax.annotation.Resource;
  17 +import java.time.Duration;
  18 +import java.util.Map;
  19 +import java.util.Set;
  20 +
  21 +import static cn.hutool.core.util.RandomUtil.randomEle;
  22 +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
  23 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
  24 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  25 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  26 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  27 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
  28 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  29 +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS;
  30 +import static java.util.Arrays.asList;
  31 +import static java.util.Collections.singletonList;
  32 +import static org.junit.jupiter.api.Assertions.*;
  33 +
  34 +/**
  35 +* {@link RewardActivityServiceImpl} 的单元测试类
  36 +*
  37 +* @author 芋道源码
  38 +*/
  39 +@Import(RewardActivityServiceImpl.class)
  40 +public class RewardActivityServiceImplTest extends BaseDbUnitTest {
  41 +
  42 + @Resource
  43 + private RewardActivityServiceImpl rewardActivityService;
  44 +
  45 + @Resource
  46 + private RewardActivityMapper rewardActivityMapper;
  47 +
  48 + @Test
  49 + public void testCreateRewardActivity_success() {
  50 + // 准备参数
  51 + RewardActivityCreateReqVO reqVO = randomPojo(RewardActivityCreateReqVO.class, o -> {
  52 + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType());
  53 + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope());
  54 + // 用于触发进行中的状态
  55 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2)));
  56 + });
  57 +
  58 + // 调用
  59 + Long rewardActivityId = rewardActivityService.createRewardActivity(reqVO);
  60 + // 断言
  61 + assertNotNull(rewardActivityId);
  62 + // 校验记录的属性是否正确
  63 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(rewardActivityId);
  64 + assertPojoEquals(reqVO, rewardActivity, "rules");
  65 + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus());
  66 + for (int i = 0; i < reqVO.getRules().size(); i++) {
  67 + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i));
  68 + }
  69 + }
  70 +
  71 + @Test
  72 + public void testUpdateRewardActivity_success() {
  73 + // mock 数据
  74 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus()));
  75 + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据
  76 + // 准备参数
  77 + RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class, o -> {
  78 + o.setId(dbRewardActivity.getId()); // 设置更新的 ID
  79 + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType());
  80 + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope());
  81 + // 用于触发进行中的状态
  82 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2)));
  83 + });
  84 +
  85 + // 调用
  86 + rewardActivityService.updateRewardActivity(reqVO);
  87 + // 校验是否更新正确
  88 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(reqVO.getId()); // 获取最新的
  89 + assertPojoEquals(reqVO, rewardActivity, "rules");
  90 + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus());
  91 + for (int i = 0; i < reqVO.getRules().size(); i++) {
  92 + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i));
  93 + }
  94 + }
  95 +
  96 + @Test
  97 + public void testCloseRewardActivity() {
  98 + // mock 数据
  99 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus()));
  100 + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据
  101 + // 准备参数
  102 + Long id = dbRewardActivity.getId();
  103 +
  104 + // 调用
  105 + rewardActivityService.closeRewardActivity(id);
  106 + // 校验状态
  107 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(id);
  108 + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus());
  109 + }
  110 +
  111 + @Test
  112 + public void testUpdateRewardActivity_notExists() {
  113 + // 准备参数
  114 + RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class);
  115 +
  116 + // 调用, 并断言异常
  117 + assertServiceException(() -> rewardActivityService.updateRewardActivity(reqVO), REWARD_ACTIVITY_NOT_EXISTS);
  118 + }
  119 +
  120 + @Test
  121 + public void testDeleteRewardActivity_success() {
  122 + // mock 数据
  123 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()));
  124 + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据
  125 + // 准备参数
  126 + Long id = dbRewardActivity.getId();
  127 +
  128 + // 调用
  129 + rewardActivityService.deleteRewardActivity(id);
  130 + // 校验数据不存在了
  131 + assertNull(rewardActivityMapper.selectById(id));
  132 + }
  133 +
  134 + @Test
  135 + public void testDeleteRewardActivity_notExists() {
  136 + // 准备参数
  137 + Long id = randomLongId();
  138 +
  139 + // 调用, 并断言异常
  140 + assertServiceException(() -> rewardActivityService.deleteRewardActivity(id), REWARD_ACTIVITY_NOT_EXISTS);
  141 + }
  142 +
  143 + @Test
  144 + public void testGetRewardActivityPage() {
  145 + // mock 数据
  146 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到
  147 + o.setName("芋艿");
  148 + o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
  149 + });
  150 + rewardActivityMapper.insert(dbRewardActivity);
  151 + // 测试 name 不匹配
  152 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName("土豆")));
  153 + // 测试 status 不匹配
  154 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus())));
  155 + // 准备参数
  156 + RewardActivityPageReqVO reqVO = new RewardActivityPageReqVO();
  157 + reqVO.setName("芋艿");
  158 + reqVO.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus());
  159 +
  160 + // 调用
  161 + PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(reqVO);
  162 + // 断言
  163 + assertEquals(1, pageResult.getTotal());
  164 + assertEquals(1, pageResult.getList().size());
  165 + assertPojoEquals(dbRewardActivity, pageResult.getList().get(0), "rules");
  166 + }
  167 +
  168 + @Test
  169 + public void testGetRewardActivities_all() {
  170 + // mock 数据
  171 + RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus())
  172 + .setProductScope(PromotionProductScopeEnum.ALL.getScope()));
  173 + rewardActivityMapper.insert(allActivity);
  174 + RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus())
  175 + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L)));
  176 + rewardActivityMapper.insert(productActivity);
  177 + // 准备参数
  178 + Set<Long> spuIds = asSet(1L, 2L);
  179 +
  180 + // 调用
  181 + Map<RewardActivityDO, Set<Long>> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds);
  182 + // 断言
  183 + assertEquals(matchRewardActivities.size(), 1);
  184 + Map.Entry<RewardActivityDO, Set<Long>> next = matchRewardActivities.entrySet().iterator().next();
  185 + assertPojoEquals(next.getKey(), allActivity);
  186 + assertEquals(next.getValue(), spuIds);
  187 + }
  188 +
  189 + @Test
  190 + public void testGetRewardActivities_product() {
  191 + // mock 数据
  192 + RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus())
  193 + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L)));
  194 + rewardActivityMapper.insert(productActivity01);
  195 + RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus())
  196 + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(singletonList(3L)));
  197 + rewardActivityMapper.insert(productActivity02);
  198 + // 准备参数
  199 + Set<Long> spuIds = asSet(1L, 2L, 3L);
  200 +
  201 + // 调用
  202 + Map<RewardActivityDO, Set<Long>> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds);
  203 + // 断言
  204 + assertEquals(matchRewardActivities.size(), 2);
  205 + matchRewardActivities.forEach((activity, activitySpuIds) -> {
  206 + if (activity.getId().equals(productActivity01.getId())) {
  207 + assertPojoEquals(activity, productActivity01);
  208 + assertEquals(activitySpuIds, asSet(1L, 2L));
  209 + } else if (activity.getId().equals(productActivity02.getId())) {
  210 + assertPojoEquals(activity, productActivity02);
  211 + assertEquals(activitySpuIds, asSet(3L));
  212 + } else {
  213 + fail();
  214 + }
  215 + });
  216 + }
  217 +
  218 +}
yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql
1 DELETE FROM "market_activity"; 1 DELETE FROM "market_activity";
  2 +DELETE FROM "promotion_coupon_template";
  3 +DELETE FROM "promotion_coupon";
  4 +DELETE FROM "promotion_reward_activity";
  5 +DELETE FROM "promotion_discount_activity";
  6 +DELETE FROM "promotion_discount_product";
yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql
@@ -16,4 +16,109 @@ CREATE TABLE IF NOT EXISTS &quot;market_activity&quot; ( @@ -16,4 +16,109 @@ CREATE TABLE IF NOT EXISTS &quot;market_activity&quot; (
16 "deleted" bit NOT NULL DEFAULT FALSE, 16 "deleted" bit NOT NULL DEFAULT FALSE,
17 "tenant_id" bigint(20) NOT NULL, 17 "tenant_id" bigint(20) NOT NULL,
18 PRIMARY KEY ("id") 18 PRIMARY KEY ("id")
19 - ) COMMENT '促销活动';  
20 \ No newline at end of file 19 \ No newline at end of file
  20 + ) COMMENT '促销活动';
  21 +
  22 +CREATE TABLE IF NOT EXISTS "promotion_coupon_template" (
  23 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  24 + "name" varchar NOT NULL,
  25 + "status" int NOT NULL,
  26 + "total_count" int NOT NULL,
  27 + "take_limit_count" int NOT NULL,
  28 + "take_type" int NOT NULL,
  29 + "use_price" int NOT NULL,
  30 + "product_scope" int NOT NULL,
  31 + "product_spu_ids" varchar,
  32 + "validity_type" int NOT NULL,
  33 + "valid_start_time" datetime,
  34 + "valid_end_time" datetime,
  35 + "fixed_start_term" int,
  36 + "fixed_end_term" int,
  37 + "discount_type" int NOT NULL,
  38 + "discount_percent" int,
  39 + "discount_price" int,
  40 + "discount_limit_price" int,
  41 + "take_count" int NOT NULL DEFAULT 0,
  42 + "use_count" int NOT NULL DEFAULT 0,
  43 + "creator" varchar DEFAULT '',
  44 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  45 + "updater" varchar DEFAULT '',
  46 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  47 + "deleted" bit NOT NULL DEFAULT FALSE,
  48 + PRIMARY KEY ("id")
  49 +) COMMENT '优惠劵模板';
  50 +
  51 +CREATE TABLE IF NOT EXISTS "promotion_coupon" (
  52 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  53 + "template_id" bigint NOT NULL,
  54 + "name" varchar NOT NULL,
  55 + "status" int NOT NULL,
  56 + "user_id" bigint NOT NULL,
  57 + "take_type" int NOT NULL,
  58 + "useprice" int NOT NULL,
  59 + "valid_start_time" datetime NOT NULL,
  60 + "valid_end_time" datetime NOT NULL,
  61 + "product_scope" int NOT NULL,
  62 + "product_spu_ids" varchar,
  63 + "discount_type" int NOT NULL,
  64 + "discount_percent" int,
  65 + "discount_price" int,
  66 + "discount_limit_price" int,
  67 + "use_order_id" bigint,
  68 + "use_time" datetime,
  69 + "creator" varchar DEFAULT '',
  70 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  71 + "updater" varchar DEFAULT '',
  72 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  73 + "deleted" bit NOT NULL DEFAULT FALSE,
  74 + PRIMARY KEY ("id")
  75 +) COMMENT '优惠劵';
  76 +
  77 +CREATE TABLE IF NOT EXISTS "promotion_reward_activity" (
  78 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  79 + "name" varchar NOT NULL,
  80 + "status" int NOT NULL,
  81 + "start_time" datetime NOT NULL,
  82 + "end_time" datetime NOT NULL,
  83 + "remark" varchar,
  84 + "condition_type" int NOT NULL,
  85 + "product_scope" int NOT NULL,
  86 + "product_spu_ids" varchar,
  87 + "rules" varchar,
  88 + "creator" varchar DEFAULT '',
  89 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  90 + "updater" varchar DEFAULT '',
  91 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  92 + "deleted" bit NOT NULL DEFAULT FALSE,
  93 + PRIMARY KEY ("id")
  94 +) COMMENT '满减送活动';
  95 +
  96 +CREATE TABLE IF NOT EXISTS "promotion_discount_activity" (
  97 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  98 + "name" varchar NOT NULL,
  99 + "status" int NOT NULL,
  100 + "start_time" datetime NOT NULL,
  101 + "end_time" datetime NOT NULL,
  102 + "remark" varchar,
  103 + "creator" varchar DEFAULT '',
  104 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  105 + "updater" varchar DEFAULT '',
  106 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  107 + "deleted" bit NOT NULL DEFAULT FALSE,
  108 + PRIMARY KEY ("id")
  109 +) COMMENT '限时折扣活动';
  110 +
  111 +CREATE TABLE IF NOT EXISTS "promotion_discount_product" (
  112 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  113 + "activity_id" bigint NOT NULL,
  114 + "spu_id" bigint NOT NULL,
  115 + "sku_id" bigint NOT NULL,
  116 + "discount_type" int NOT NULL,
  117 + "discount_percent" int,
  118 + "discount_price" int,
  119 + "creator" varchar DEFAULT '',
  120 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  121 + "updater" varchar DEFAULT '',
  122 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  123 + "deleted" bit NOT NULL DEFAULT FALSE,
  124 + PRIMARY KEY ("id")
  125 +) COMMENT '限时折扣活动';
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
@@ -43,13 +43,12 @@ public class AppTradeOrderController { @@ -43,13 +43,12 @@ public class AppTradeOrderController {
43 @PreAuthenticated 43 @PreAuthenticated
44 public CommonResult<Long> createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, 44 public CommonResult<Long> createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO,
45 HttpServletRequest servletRequest) { 45 HttpServletRequest servletRequest) {
46 - // 获取登录用户 46 + // 获取登录用户、用户 IP 地址
47 Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); 47 Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
48 - // 获取用户ip地址  
49 String clientIp = ServletUtil.getClientIP(servletRequest); 48 String clientIp = ServletUtil.getClientIP(servletRequest);
50 // 创建交易订单,预支付记录 49 // 创建交易订单,预支付记录
51 - Long result = tradeOrderService.createTradeOrder(loginUserId, clientIp, createReqVO);  
52 - return CommonResult.success(result); 50 + Long orderId = tradeOrderService.createTradeOrder(loginUserId, clientIp, createReqVO);
  51 + return CommonResult.success(orderId);
53 } 52 }
54 53
55 @GetMapping("/get") 54 @GetMapping("/get")
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java
@@ -19,7 +19,7 @@ public class AppTradeOrderCreateReqVO { @@ -19,7 +19,7 @@ public class AppTradeOrderCreateReqVO {
19 @ApiModelProperty(name = "优惠劵编号", example = "1024") 19 @ApiModelProperty(name = "优惠劵编号", example = "1024")
20 private Long couponId; 20 private Long couponId;
21 21
22 - @ApiModelProperty(name = "备注", example = "1024") 22 + @ApiModelProperty(name = "备注", example = "这个是我的订单哟")
23 private String remark; 23 private String remark;
24 24
25 @ApiModelProperty(name = "是否来自购物车", required = true, example = "true", notes = "true - 来自购物车;false - 立即购买") 25 @ApiModelProperty(name = "是否来自购物车", required = true, example = "true", notes = "true - 来自购物车;false - 立即购买")
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.trade.dal.dataobject.order;
2 2
3 import cn.iocoder.yudao.framework.common.enums.TerminalEnum; 3 import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  5 +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO.OrderItem;
5 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; 6 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum;
6 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; 7 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
7 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 8 import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
@@ -74,7 +75,7 @@ public class TradeOrderDO extends BaseDO { @@ -74,7 +75,7 @@ public class TradeOrderDO extends BaseDO {
74 /** 75 /**
75 * 购买的商品数量 76 * 购买的商品数量
76 */ 77 */
77 - private Integer productCount; // total_num 78 + private Integer productCount;
78 /** 79 /**
79 * 订单完成时间 80 * 订单完成时间
80 */ 81 */
@@ -116,14 +117,25 @@ public class TradeOrderDO extends BaseDO { @@ -116,14 +117,25 @@ public class TradeOrderDO extends BaseDO {
116 * 商品原价(总),单位:分 117 * 商品原价(总),单位:分
117 * 118 *
118 * 基于 {@link TradeOrderItemDO#getTotalOriginalPrice()} 求和 119 * 基于 {@link TradeOrderItemDO#getTotalOriginalPrice()} 求和
  120 + *
  121 + * 对应 taobao 的 trade.total_fee 字段
119 */ 122 */
120 private Integer originalPrice; 123 private Integer originalPrice;
121 /** 124 /**
  125 + * 订单原价(总),单位:分
  126 + *
  127 + * 基于 {@link OrderItem#getPayPrice()} 求和
  128 + * 和 {@link #originalPrice} 的差异:去除商品级优惠
  129 + */
  130 + private Integer orderPrice;
  131 + /**
122 * 订单优惠(总),单位:分 132 * 订单优惠(总),单位:分
123 * 133 *
124 - * 例如说:满减折扣;不包括优惠劵、商品优惠(TODO) 134 + * 订单级优惠:对主订单的优惠,常见如:订单满 200 元减 10 元;订单满 80 包邮。
  135 + *
  136 + * 对应 taobao 的 order.discount_fee 字段
125 */ 137 */
126 - private Integer promotionPrice; 138 + private Integer discountPrice;
127 /** 139 /**
128 * 运费金额,单位:分 140 * 运费金额,单位:分
129 */ 141 */
@@ -137,12 +149,12 @@ public class TradeOrderDO extends BaseDO { @@ -137,12 +149,12 @@ public class TradeOrderDO extends BaseDO {
137 /** 149 /**
138 * 应付金额(总),单位:分 150 * 应付金额(总),单位:分
139 * 151 *
140 - * = {@link #originalPrice}  
141 - * + {@link #deliveryPrice}  
142 - * + {@link #adjustPrice}  
143 - * - {@link #promotionPrice} 152 + * = {@link OrderItem#getPayPrice()} 求和
144 * - {@link #couponPrice} 153 * - {@link #couponPrice}
145 * - {@link #pointPrice} 154 * - {@link #pointPrice}
  155 + * + {@link #deliveryPrice}
  156 + * - {@link #discountPrice}
  157 + * + {@link #adjustPrice}
146 */ 158 */
147 private Integer payPrice; 159 private Integer payPrice;
148 /** 160 /**
@@ -164,11 +176,11 @@ public class TradeOrderDO extends BaseDO { @@ -164,11 +176,11 @@ public class TradeOrderDO extends BaseDO {
164 * 176 *
165 * 关联 DeliveryTemplateDO 的 id 编号 177 * 关联 DeliveryTemplateDO 的 id 编号
166 */ 178 */
167 - private Long deliveryTemplateId; // dvy_id 179 + private Long deliveryTemplateId;
168 /** 180 /**
169 * 物流公司单号 181 * 物流公司单号
170 */ 182 */
171 - private String expressNo; // dvy_flow_id 183 + private String expressNo;
172 /** 184 /**
173 * 发货状态 185 * 发货状态
174 * 186 *
@@ -227,10 +239,14 @@ public class TradeOrderDO extends BaseDO { @@ -227,10 +239,14 @@ public class TradeOrderDO extends BaseDO {
227 private Long couponId; 239 private Long couponId;
228 /** 240 /**
229 * 优惠劵减免金额,单位:分 241 * 优惠劵减免金额,单位:分
  242 + *
  243 + * 对应 taobao 的 trade.coupon_fee 字段
230 */ 244 */
231 private Integer couponPrice; 245 private Integer couponPrice;
232 /** 246 /**
233 * 积分抵扣的金额,单位:分 247 * 积分抵扣的金额,单位:分
  248 + *
  249 + * 对应 taobao 的 trade.point_fee 字段
234 */ 250 */
235 private Integer pointPrice; 251 private Integer pointPrice;
236 252
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
@@ -71,7 +71,7 @@ public class TradeOrderItemDO extends BaseDO { @@ -71,7 +71,7 @@ public class TradeOrderItemDO extends BaseDO {
71 */ 71 */
72 private Integer count; 72 private Integer count;
73 /** 73 /**
74 - * 是否评论 74 + * 是否评论 TODO
75 * 75 *
76 * false - 未评论 76 * false - 未评论
77 * true - 已评论 77 * true - 已评论
@@ -79,61 +79,61 @@ public class TradeOrderItemDO extends BaseDO { @@ -79,61 +79,61 @@ public class TradeOrderItemDO extends BaseDO {
79 private Boolean commented; 79 private Boolean commented;
80 80
81 // ========== 价格 + 支付基本信息 ========== 81 // ========== 价格 + 支付基本信息 ==========
  82 +
82 /** 83 /**
83 - * 商品原价(单),单位:分 84 + * 商品原价(总),单位:分
84 * 85 *
85 - * 对应 ProductSkuDO 的 price 字段 86 + * = {@link #originalUnitPrice} * {@link #getCount()}
86 */ 87 */
87 - // like - original_price;niu - costPrice  
88 private Integer originalPrice; 88 private Integer originalPrice;
89 /** 89 /**
90 - * 商品原价(总),单位:分 90 + * 商品原价(单),单位:分
91 * 91 *
92 - * = {@link #originalPrice} * {@link #count} 92 + * 对应 ProductSkuDO 的 price 字段
  93 + * 对应 taobao 的 order.price 字段
93 */ 94 */
94 - // like - total_price;niu - 暂无  
95 - private Integer totalOriginalPrice; 95 + private Integer originalUnitPrice;
96 /** 96 /**
97 - * 商品级优惠(总),单位:分 97 + * 商品优惠(总),单位:分
  98 + *
  99 + * 商品级优惠:对单个商品的,常见如:商品原价的 8 折;商品原价的减 50 元
98 * 100 *
99 - * 例如说“限时折扣”:商品原价的 8 折;商品原价的减 50 元 101 + * 对应 taobao 的 order.discount_fee 字段
100 */ 102 */
101 - // taobao - order.discount_fee(子订单商品优惠)  
102 - private Integer totalPromotionPrice; 103 + private Integer discountPrice;
103 /** 104 /**
104 - * 最终购买金额(单),单位:分。 105 + * 子订单实付金额,不算主订单分摊金额,单位:分
  106 + *
  107 + * = {@link #originalPrice}
  108 + * - {@link #discountPrice}
105 * 109 *
106 - * = {@link #totalPresentPrice} / {@link #count} 110 + * 对应 taobao 的 order.payment 字段
107 */ 111 */
108 - private Integer presentPrice; 112 + private Integer payPrice;
  113 +
109 /** 114 /**
110 - * 最终购买金额(总),单位:分。 115 + * 子订单分摊金额(总),单位:分
  116 + * 需要分摊 {@link TradeOrderDO#getDiscountPrice()}、{@link TradeOrderDO#getCouponPrice()}、{@link TradeOrderDO#getPointPrice()}
111 * 117 *
112 - * = {@link #totalOriginalPrice}  
113 - * - {@link #totalPromotionPrice} 118 + * 对应 taobao 的 order.part_mjz_discount 字段
  119 + * 淘宝说明:子订单分摊优惠基础逻辑:一般正常优惠券和满减优惠按照子订单的金额进行分摊,特殊情况如果优惠券是指定商品使用的,只会分摊到对应商品子订单上不分摊。
114 */ 120 */
115 - // like - total_pay_price;niu - goods_money; taobao - order.payment(子订单实付金额,不算主订单分摊金额) | order.total_fee(子订单应付金额,参考使用)  
116 - private Integer totalPresentPrice;  
117 - // TODO 芋艿:part_mjz_discount(子订单分摊金额);本质上,totalOriginalPrice - totalPayPrice 121 + private Integer orderPartPrice;
118 /** 122 /**
119 - * 应付金额(总),单位:分 123 + * 分摊后子订单实付金额(总),单位:分
  124 + *
  125 + * = {@link #payPrice}
  126 + * - {@link #orderPartPrice}
  127 + *
  128 + * 对应 taobao 的 divide_order_fee 字段
120 */ 129 */
121 - // taobao - divide_order_fee (分摊后子订单实付金额);  
122 - private Integer totalPayPrice; 130 + private Integer orderDividePrice;
123 131
124 // ========== 营销基本信息 ========== 132 // ========== 营销基本信息 ==========
125 -// /**  
126 -// * 积分抵扣的金额,单位:分  
127 -// */  
128 -// private Integer integralTotal; // like - integral_price;niu - point_money  
129 -// /**  
130 -// * 使用的积分  
131 -// */  
132 -// private Integer useIntegral; // niu - use_point  
133 133
134 // ========== 退款基本信息 ========== 134 // ========== 退款基本信息 ==========
135 /** 135 /**
136 - * 退款状态 136 + * 退款状态 TODO
137 * 137 *
138 * 枚举 {@link TradeOrderItemRefundStatusEnum} 138 * 枚举 {@link TradeOrderItemRefundStatusEnum}
139 */ 139 */
@@ -148,7 +148,7 @@ public class TradeOrderItemDO extends BaseDO { @@ -148,7 +148,7 @@ public class TradeOrderItemDO extends BaseDO {
148 // presentTotal = buyTotal - discountTotal = 24 - 11 = 13 148 // presentTotal = buyTotal - discountTotal = 24 - 11 = 13
149 // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 149 // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33
150 /** 150 /**
151 - * 退款总金额,单位:分 151 + * 退款总金额,单位:分 TODO
152 */ 152 */
153 private Integer refundTotal; 153 private Integer refundTotal;
154 154
@@ -173,42 +173,5 @@ public class TradeOrderItemDO extends BaseDO { @@ -173,42 +173,5 @@ public class TradeOrderItemDO extends BaseDO {
173 173
174 } 174 }
175 175
176 - // TODO 芋艿:basket_date 加入购物车时间;  
177 - // TODO 芋艿:distribution_card_no 推广员使用的推销卡号  
178 -  
179 - // TODO 待确定:mf  
180 - // TODO give_integral:赠送积分  
181 - // TODO is_reply:是否评价,0-未评价,1-已评价  
182 - // TODO is_sub:是否单独分佣,0-否,1-是  
183 - // TODO vip_price:会员价  
184 - // TODO product_type:商品类型:0-普通,1-秒杀,2-砍价,3-拼团,4-视频号  
185 -  
186 - // TODO 待确定:lf  
187 - // TODO integral_price:积分抵扣的金额  
188 - // TODO member_price:会员价格  
189 - // TODO is_member:是否为会员折扣;0-不是;1-是  
190 - // TODO member_discount:会员折扣(百分比)  
191 -  
192 - // TODO goods_info 商品信息  
193 -  
194 - // TODO integral_price:积分抵扣的金额  
195 -  
196 - // TODO 待确定:niu  
197 - // TODO is_virtual '是否是虚拟商品'  
198 - // TODO goods_class '商品种类(1.实物 2.虚拟3.卡券)'  
199 - // TODO adjust_money ''调整金额''  
200 -  
201 - // TODO is_fenxiao 是否分销,  
202 - // TODO adjust_money 是否分销,  
203 -  
204 - // TODO delivery_status '配送状态'  
205 - // TODO delivery_no ''配送单号''  
206 - // TODO gift_flag '赠品标识'  
207 - // TODO gift_flag '赠品标识'  
208 -  
209 - // TODO refund_status '退款状态'  
210 - // TODO refund_type '退款状态'  
211 - // TODO 一堆退款字段  
212 -  
213 } 176 }
214 177
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java
@@ -3,18 +3,20 @@ package cn.iocoder.yudao.module.trade.service.order; @@ -3,18 +3,20 @@ package cn.iocoder.yudao.module.trade.service.order;
3 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; 3 import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
4 4
5 /** 5 /**
6 - * TODO @LeeYan9: 类注释 6 + * 交易订单 Service 接口
  7 + *
7 * @author LeeYan9 8 * @author LeeYan9
8 * @since 2022-08-26 9 * @since 2022-08-26
9 */ 10 */
10 public interface TradeOrderService { 11 public interface TradeOrderService {
11 12
12 /** 13 /**
13 - * 创建交易订单 TODO @LeeYan9: 方法注释, 和参数要空一行 14 + * 创建交易订单
  15 + *
14 * @param loginUserId 登录用户 16 * @param loginUserId 登录用户
15 - * @param clientIp 用户ip地址 // TODO @LeeYan9: 中英文之间, 空一行哈 17 + * @param clientIp 用户 IP 地址
16 * @param createReqVO 创建交易订单请求模型 18 * @param createReqVO 创建交易订单请求模型
17 - * @return 交易订单创建结果 19 + * @return 交易订单的编号
18 */ 20 */
19 Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO); 21 Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO);
20 } 22 }
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
@@ -45,14 +45,17 @@ import java.util.Map; @@ -45,14 +45,17 @@ import java.util.Map;
45 import java.util.Objects; 45 import java.util.Objects;
46 46
47 /** 47 /**
48 - * TODO @LeeYan9: 注释 48 + * 交易订单 Service 实现类
  49 + *
49 * @author LeeYan9 50 * @author LeeYan9
50 * @since 2022-08-26 51 * @since 2022-08-26
51 */ 52 */
52 @Service 53 @Service
53 public class TradeOrderServiceImpl implements TradeOrderService { 54 public class TradeOrderServiceImpl implements TradeOrderService {
54 55
55 - // TODO @LeeYan9: 相同类型的, 可以放在一起,不用空行; 例如说 Mapper 和 API 和 Properties 56 + // TODO LeeYan9: 静态变量, 需要在最前面哈; 另外, 静态变量的注释最好写下;
  57 + private static final String BLANK_PLACEHOLDER = " ";
  58 + private static final String MULTIPLIER_PLACEHOLDER = "x";
56 59
57 @Resource 60 @Resource
58 private TradeOrderMapper tradeOrderMapper; 61 private TradeOrderMapper tradeOrderMapper;
@@ -71,15 +74,10 @@ public class TradeOrderServiceImpl implements TradeOrderService { @@ -71,15 +74,10 @@ public class TradeOrderServiceImpl implements TradeOrderService {
71 @Resource 74 @Resource
72 private TradeOrderProperties tradeOrderProperties; 75 private TradeOrderProperties tradeOrderProperties;
73 76
74 - // TODO LeeYan9: 静态变量, 需要在最前面哈; 另外, 静态变量的注释最好写下;  
75 - private static final String BLANK_PLACEHOLDER = " ";  
76 - private static final String MULTIPLIER_PLACEHOLDER = "x";  
77 -  
78 @Override 77 @Override
79 @Transactional(rollbackFor = Exception.class) 78 @Transactional(rollbackFor = Exception.class)
80 public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { 79 public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) {
81 -  
82 - List<Item> items = createReqVO.getItems(); // TODO @LeeYan9: 方法第一行, 不用空哈; 80 + List<Item> items = createReqVO.getItems();
83 // 商品SKU检查 sku可售状态,库存 81 // 商品SKU检查 sku可售状态,库存
84 List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId)); 82 List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId));
85 Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId); 83 Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId);
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java
@@ -2,6 +2,12 @@ package cn.iocoder.yudao.module.member.api.user; @@ -2,6 +2,12 @@ package cn.iocoder.yudao.module.member.api.user;
2 2
3 import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; 3 import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
4 4
  5 +import java.util.Collection;
  6 +import java.util.List;
  7 +import java.util.Map;
  8 +
  9 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
  10 +
5 /** 11 /**
6 * 会员用户的 API 接口 12 * 会员用户的 API 接口
7 * 13 *
@@ -17,4 +23,30 @@ public interface MemberUserApi { @@ -17,4 +23,30 @@ public interface MemberUserApi {
17 */ 23 */
18 UserRespDTO getUser(Long id); 24 UserRespDTO getUser(Long id);
19 25
  26 + /**
  27 + * 获得会员用户信息们
  28 + *
  29 + * @param ids 用户编号的数组
  30 + * @return 用户信息们
  31 + */
  32 + List<UserRespDTO> getUsers(Collection<Long> ids);
  33 +
  34 + /**
  35 + * 获得会员用户 Map
  36 + *
  37 + * @param ids 用户编号的数组
  38 + * @return 会员用户 Map
  39 + */
  40 + default Map<Long, UserRespDTO> getUserMap(Collection<Long> ids) {
  41 + return convertMap(getUsers(ids), UserRespDTO::getId);
  42 + }
  43 +
  44 + /**
  45 + * 基于用户昵称,模糊匹配用户列表
  46 + *
  47 + * @param nickname 用户昵称,模糊匹配
  48 + * @return 用户信息的列表
  49 + */
  50 + List<UserRespDTO> getUserListByNickname(String nickname);
  51 +
20 } 52 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java
@@ -8,6 +8,8 @@ import org.springframework.stereotype.Service; @@ -8,6 +8,8 @@ import org.springframework.stereotype.Service;
8 import org.springframework.validation.annotation.Validated; 8 import org.springframework.validation.annotation.Validated;
9 9
10 import javax.annotation.Resource; 10 import javax.annotation.Resource;
  11 +import java.util.Collection;
  12 +import java.util.List;
11 13
12 /** 14 /**
13 * 会员用户的 API 实现类 15 * 会员用户的 API 实现类
@@ -27,4 +29,14 @@ public class MemberUserApiImpl implements MemberUserApi { @@ -27,4 +29,14 @@ public class MemberUserApiImpl implements MemberUserApi {
27 return UserConvert.INSTANCE.convert2(user); 29 return UserConvert.INSTANCE.convert2(user);
28 } 30 }
29 31
  32 + @Override
  33 + public List<UserRespDTO> getUsers(Collection<Long> ids) {
  34 + return UserConvert.INSTANCE.convertList2(userService.getUserList(ids));
  35 + }
  36 +
  37 + @Override
  38 + public List<UserRespDTO> getUserListByNickname(String nickname) {
  39 + return UserConvert.INSTANCE.convertList2(userService.getUserListByNickname(nickname));
  40 + }
  41 +
30 } 42 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/UserController.java deleted
1 -package cn.iocoder.yudao.module.member.controller.admin.user;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.CommonResult;  
4 -import cn.iocoder.yudao.module.member.api.user.dto.UserInfoDTO;  
5 -import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;  
6 -import cn.iocoder.yudao.module.member.convert.user.UserConvert;  
7 -import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;  
8 -import cn.iocoder.yudao.module.member.service.user.MemberUserService;  
9 -import io.swagger.annotations.Api;  
10 -import io.swagger.annotations.ApiOperation;  
11 -import lombok.extern.slf4j.Slf4j;  
12 -import org.springframework.web.bind.annotation.GetMapping;  
13 -import org.springframework.web.bind.annotation.PathVariable;  
14 -import org.springframework.web.bind.annotation.RequestMapping;  
15 -import org.springframework.web.bind.annotation.RestController;  
16 -  
17 -import javax.annotation.Resource;  
18 -  
19 -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;  
20 -  
21 -/**  
22 - * @author Banging  
23 - */  
24 -@Slf4j  
25 -@Api("用户管理")  
26 -@RestController(value = "memberUserController")  
27 -@RequestMapping("/user")  
28 -public class UserController {  
29 -  
30 - @Resource  
31 - private MemberUserService userService;  
32 -  
33 - @ApiOperation(value = "用户信息获取",notes = "用户基本信息的获取")  
34 - @GetMapping("/{tel}")  
35 - public CommonResult<UserInfoDTO> getUserInfo(@PathVariable String tel){  
36 - MemberUserDO user = userService.getUserByMobile(tel);  
37 - return CommonResult.success(UserConvert.INSTANCE.convertInfo(user));  
38 - }  
39 -}  
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java
1 package cn.iocoder.yudao.module.member.convert.user; 1 package cn.iocoder.yudao.module.member.convert.user;
2 2
3 -import cn.iocoder.yudao.module.member.api.user.dto.UserInfoDTO;  
4 import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; 3 import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO;
5 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO; 4 import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO;
6 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; 5 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
7 import org.mapstruct.Mapper; 6 import org.mapstruct.Mapper;
8 import org.mapstruct.factory.Mappers; 7 import org.mapstruct.factory.Mappers;
9 8
  9 +import java.util.List;
  10 +
10 @Mapper 11 @Mapper
11 public interface UserConvert { 12 public interface UserConvert {
12 13
@@ -15,5 +16,7 @@ public interface UserConvert { @@ -15,5 +16,7 @@ public interface UserConvert {
15 AppUserInfoRespVO convert(MemberUserDO bean); 16 AppUserInfoRespVO convert(MemberUserDO bean);
16 17
17 UserRespDTO convert2(MemberUserDO bean); 18 UserRespDTO convert2(MemberUserDO bean);
18 - UserInfoDTO convertInfo(MemberUserDO bean); 19 +
  20 + List<UserRespDTO> convertList2(List<MemberUserDO> list);
  21 +
19 } 22 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java
1 package cn.iocoder.yudao.module.member.dal.mysql.user; 1 package cn.iocoder.yudao.module.member.dal.mysql.user;
2 2
3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; 3 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
4 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; 5 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
5 import org.apache.ibatis.annotations.Mapper; 6 import org.apache.ibatis.annotations.Mapper;
6 7
  8 +import java.util.List;
  9 +
7 /** 10 /**
8 * 会员 User Mapper 11 * 会员 User Mapper
9 * 12 *
@@ -16,4 +19,9 @@ public interface MemberUserMapper extends BaseMapperX&lt;MemberUserDO&gt; { @@ -16,4 +19,9 @@ public interface MemberUserMapper extends BaseMapperX&lt;MemberUserDO&gt; {
16 return selectOne(MemberUserDO::getMobile, mobile); 19 return selectOne(MemberUserDO::getMobile, mobile);
17 } 20 }
18 21
  22 + default List<MemberUserDO> selectListByNicknameLike(String nickname) {
  23 + return selectList(new LambdaQueryWrapperX<MemberUserDO>()
  24 + .likeIfPresent(MemberUserDO::getNickname, nickname));
  25 + }
  26 +
19 } 27 }
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java
@@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobile @@ -5,6 +5,8 @@ import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserUpdateMobile
5 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; 5 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
6 6
7 import java.io.InputStream; 7 import java.io.InputStream;
  8 +import java.util.Collection;
  9 +import java.util.List;
8 10
9 /** 11 /**
10 * 会员用户 Service 接口 12 * 会员用户 Service 接口
@@ -22,6 +24,15 @@ public interface MemberUserService { @@ -22,6 +24,15 @@ public interface MemberUserService {
22 MemberUserDO getUserByMobile(String mobile); 24 MemberUserDO getUserByMobile(String mobile);
23 25
24 /** 26 /**
  27 + * 基于用户昵称,模糊匹配用户列表
  28 + *
  29 + * @param nickname 用户昵称,模糊匹配
  30 + * @return 用户信息的列表
  31 + */
  32 + List<MemberUserDO> getUserListByNickname(String nickname);
  33 +
  34 +
  35 + /**
25 * 基于手机号创建用户。 36 * 基于手机号创建用户。
26 * 如果用户已经存在,则直接进行返回 37 * 如果用户已经存在,则直接进行返回
27 * 38 *
@@ -48,6 +59,14 @@ public interface MemberUserService { @@ -48,6 +59,14 @@ public interface MemberUserService {
48 MemberUserDO getUser(Long id); 59 MemberUserDO getUser(Long id);
49 60
50 /** 61 /**
  62 + * 通过用户 ID 查询用户们
  63 + *
  64 + * @param ids 用户 ID
  65 + * @return 用户对象信息数组
  66 + */
  67 + List<MemberUserDO> getUserList(Collection<Long> ids);
  68 +
  69 + /**
51 * 修改用户昵称 70 * 修改用户昵称
52 * @param userId 用户id 71 * @param userId 用户id
53 * @param nickname 用户新昵称 72 * @param nickname 用户新昵称
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java
@@ -19,7 +19,9 @@ import org.springframework.transaction.annotation.Transactional; @@ -19,7 +19,9 @@ import org.springframework.transaction.annotation.Transactional;
19 import javax.annotation.Resource; 19 import javax.annotation.Resource;
20 import javax.validation.Valid; 20 import javax.validation.Valid;
21 import java.io.InputStream; 21 import java.io.InputStream;
  22 +import java.util.Collection;
22 import java.util.Date; 23 import java.util.Date;
  24 +import java.util.List;
23 25
24 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 26 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
25 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; 27 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
@@ -52,6 +54,11 @@ public class MemberUserServiceImpl implements MemberUserService { @@ -52,6 +54,11 @@ public class MemberUserServiceImpl implements MemberUserService {
52 } 54 }
53 55
54 @Override 56 @Override
  57 + public List<MemberUserDO> getUserListByNickname(String nickname) {
  58 + return memberUserMapper.selectListByNicknameLike(nickname);
  59 + }
  60 +
  61 + @Override
55 public MemberUserDO createUserIfAbsent(String mobile, String registerIp) { 62 public MemberUserDO createUserIfAbsent(String mobile, String registerIp) {
56 // 用户已经存在 63 // 用户已经存在
57 MemberUserDO user = memberUserMapper.selectByMobile(mobile); 64 MemberUserDO user = memberUserMapper.selectByMobile(mobile);
@@ -87,6 +94,11 @@ public class MemberUserServiceImpl implements MemberUserService { @@ -87,6 +94,11 @@ public class MemberUserServiceImpl implements MemberUserService {
87 } 94 }
88 95
89 @Override 96 @Override
  97 + public List<MemberUserDO> getUserList(Collection<Long> ids) {
  98 + return memberUserMapper.selectBatchIds(ids);
  99 + }
  100 +
  101 + @Override
90 public void updateUserNickname(Long userId, String nickname) { 102 public void updateUserNickname(Long userId, String nickname) {
91 MemberUserDO user = this.checkUserExists(userId); 103 MemberUserDO user = this.checkUserExists(userId);
92 // 仅当新昵称不等于旧昵称时进行修改 104 // 仅当新昵称不等于旧昵称时进行修改
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleUpdateStatusReqVO.java
1 package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; 1 package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
3 import io.swagger.annotations.ApiModel; 5 import io.swagger.annotations.ApiModel;
4 import io.swagger.annotations.ApiModelProperty; 6 import io.swagger.annotations.ApiModelProperty;
5 import lombok.Data; 7 import lombok.Data;
@@ -16,7 +18,7 @@ public class RoleUpdateStatusReqVO { @@ -16,7 +18,7 @@ public class RoleUpdateStatusReqVO {
16 18
17 @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举") 19 @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举")
18 @NotNull(message = "状态不能为空") 20 @NotNull(message = "状态不能为空")
19 -// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") 21 + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
20 private Integer status; 22 private Integer status;
21 23
22 } 24 }
yudao-server/src/main/resources/application-local.yaml
@@ -174,6 +174,7 @@ logging: @@ -174,6 +174,7 @@ logging:
174 cn.iocoder.yudao.module.tool.dal.mysql: debug 174 cn.iocoder.yudao.module.tool.dal.mysql: debug
175 cn.iocoder.yudao.module.member.dal.mysql: debug 175 cn.iocoder.yudao.module.member.dal.mysql: debug
176 cn.iocoder.yudao.module.trade.dal.mysql: debug 176 cn.iocoder.yudao.module.trade.dal.mysql: debug
  177 + cn.iocoder.yudao.module.promotion.dal.mysql: debug
177 178
178 --- #################### 微信公众号、小程序相关配置 #################### 179 --- #################### 微信公众号、小程序相关配置 ####################
179 wx: 180 wx:
yudao-ui-admin/src/api/mall/product/sku.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获得商品 SKU 选项的列表
  4 +export function getSkuOptionList() {
  5 + return request({
  6 + url: '/product/sku/get-option-list',
  7 + method: 'get',
  8 + })
  9 +}
yudao-ui-admin/src/api/mall/product/spu.js
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 2
3 -// 创建商品spu 3 +// 创建商品 SPU
4 export function createSpu(data) { 4 export function createSpu(data) {
5 return request({ 5 return request({
6 url: '/product/spu/create', 6 url: '/product/spu/create',
@@ -9,7 +9,7 @@ export function createSpu(data) { @@ -9,7 +9,7 @@ export function createSpu(data) {
9 }) 9 })
10 } 10 }
11 11
12 -// 更新商品spu 12 +// 更新商品 SPU
13 export function updateSpu(data) { 13 export function updateSpu(data) {
14 return request({ 14 return request({
15 url: '/product/spu/update', 15 url: '/product/spu/update',
@@ -18,7 +18,7 @@ export function updateSpu(data) { @@ -18,7 +18,7 @@ export function updateSpu(data) {
18 }) 18 })
19 } 19 }
20 20
21 -// 删除商品spu 21 +// 删除商品 SPU
22 export function deleteSpu(id) { 22 export function deleteSpu(id) {
23 return request({ 23 return request({
24 url: '/product/spu/delete?id=' + id, 24 url: '/product/spu/delete?id=' + id,
@@ -34,7 +34,7 @@ export function getSpu(id) { @@ -34,7 +34,7 @@ export function getSpu(id) {
34 }) 34 })
35 } 35 }
36 36
37 -// 获得商品spu详情 37 +// 获得商品 SPU 详情
38 export function getSpuDetail(id) { 38 export function getSpuDetail(id) {
39 return request({ 39 return request({
40 url: '/product/spu/get/detail?id=' + id, 40 url: '/product/spu/get/detail?id=' + id,
@@ -42,7 +42,7 @@ export function getSpuDetail(id) { @@ -42,7 +42,7 @@ export function getSpuDetail(id) {
42 }) 42 })
43 } 43 }
44 44
45 -// 获得商品spu分页 45 +// 获得商品 SPU 分页
46 export function getSpuPage(query) { 46 export function getSpuPage(query) {
47 return request({ 47 return request({
48 url: '/product/spu/page', 48 url: '/product/spu/page',
@@ -50,3 +50,11 @@ export function getSpuPage(query) { @@ -50,3 +50,11 @@ export function getSpuPage(query) {
50 params: query 50 params: query
51 }) 51 })
52 } 52 }
  53 +
  54 +// 获得商品 SPU 精简列表
  55 +export function getSpuSimpleList() {
  56 + return request({
  57 + url: '/product/spu/get-simple-list',
  58 + method: 'get',
  59 + })
  60 +}
yudao-ui-admin/src/api/mall/promotion/coupon.js 0 → 100755
  1 +import request from '@/utils/request'
  2 +
  3 +// 删除优惠劵
  4 +export function deleteCoupon(id) {
  5 + return request({
  6 + url: '/promotion/coupon/delete?id=' + id,
  7 + method: 'delete'
  8 + })
  9 +}
  10 +
  11 +// 获得优惠劵分页
  12 +export function getCouponPage(query) {
  13 + return request({
  14 + url: '/promotion/coupon/page',
  15 + method: 'get',
  16 + params: query
  17 + })
  18 +}
yudao-ui-admin/src/api/promotion/couponTemplate.js renamed to yudao-ui-admin/src/api/mall/promotion/couponTemplate.js
@@ -18,6 +18,19 @@ export function updateCouponTemplate(data) { @@ -18,6 +18,19 @@ export function updateCouponTemplate(data) {
18 }) 18 })
19 } 19 }
20 20
  21 +// 更新优惠劵模板的状态
  22 +export function updateCouponTemplateStatus(id, status) {
  23 + const data = {
  24 + id,
  25 + status
  26 + }
  27 + return request({
  28 + url: '/promotion/coupon-template/update-status',
  29 + method: 'put',
  30 + data: data
  31 + })
  32 +}
  33 +
21 // 删除优惠劵模板 34 // 删除优惠劵模板
22 export function deleteCouponTemplate(id) { 35 export function deleteCouponTemplate(id) {
23 return request({ 36 return request({
yudao-ui-admin/src/api/mall/CouponTemplete/CouponTemplete.js renamed to yudao-ui-admin/src/api/mall/promotion/discountActivity.js 100644 → 100755
1 import request from '@/utils/request' 1 import request from '@/utils/request'
2 2
3 -// 创建优惠券模板  
4 -export function create(data) { 3 +// 创建限时折扣活动
  4 +export function createDiscountActivity(data) {
5 return request({ 5 return request({
6 - url: '/coupon/template/create', 6 + url: '/promotion/discount-activity/create',
7 method: 'post', 7 method: 'post',
8 data: data 8 data: data
9 }) 9 })
10 } 10 }
11 11
12 -// 更新优惠券模板  
13 -export function update(data) { 12 +// 更新限时折扣活动
  13 +export function updateDiscountActivity(data) {
14 return request({ 14 return request({
15 - url: '/coupon/template/update', 15 + url: '/promotion/discount-activity/update',
16 method: 'put', 16 method: 'put',
17 data: data 17 data: data
18 }) 18 })
19 } 19 }
20 20
21 -// 删除优惠券模板  
22 -export function deleteCouponTemplete (id) { 21 +// 关闭限时折扣活动
  22 +export function closeDiscountActivity(id) {
23 return request({ 23 return request({
24 - url: '/coupon/template/delete?id=' + id,  
25 - method: 'delete' 24 + url: '/promotion/discount-activity/close?id=' + id,
  25 + method: 'put'
26 }) 26 })
27 } 27 }
28 28
29 -// 获得优惠券模板  
30 -export function get(id) { 29 +// 删除限时折扣活动
  30 +export function deleteDiscountActivity(id) {
31 return request({ 31 return request({
32 - url: '/coupon/template/get?id=' + id,  
33 - method: 'get' 32 + url: '/promotion/discount-activity/delete?id=' + id,
  33 + method: 'delete'
34 }) 34 })
35 } 35 }
36 36
37 -// 获得优惠券模板分页  
38 -export function getPage(query) { 37 +// 获得限时折扣活动
  38 +export function getDiscountActivity(id) {
39 return request({ 39 return request({
40 - url: '/coupon/template/page',  
41 - method: 'get',  
42 - params: query 40 + url: '/promotion/discount-activity/get?id=' + id,
  41 + method: 'get'
43 }) 42 })
44 } 43 }
45 44
46 -// 导出优惠券模板 Excel  
47 -export function exportExcel(query) { 45 +// 获得限时折扣活动分页
  46 +export function getDiscountActivityPage(query) {
48 return request({ 47 return request({
49 - url: '/coupon/template/export-excel', 48 + url: '/promotion/discount-activity/page',
50 method: 'get', 49 method: 'get',
51 - params: query,  
52 - responseType: 'blob' 50 + params: query
53 }) 51 })
54 } 52 }
yudao-ui-admin/src/api/mall/promotion/rewardActivity.js 0 → 100755
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建满减送活动
  4 +export function createRewardActivity(data) {
  5 + return request({
  6 + url: '/promotion/reward-activity/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新满减送活动
  13 +export function updateRewardActivity(data) {
  14 + return request({
  15 + url: '/promotion/reward-activity/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 关闭满减送活动
  22 +export function closeRewardActivity(id) {
  23 + return request({
  24 + url: '/promotion/reward-activity/close?id=' + id,
  25 + method: 'put'
  26 + })
  27 +}
  28 +
  29 +// 删除满减送活动
  30 +export function deleteRewardActivity(id) {
  31 + return request({
  32 + url: '/promotion/reward-activity/delete?id=' + id,
  33 + method: 'delete'
  34 + })
  35 +}
  36 +
  37 +// 获得满减送活动
  38 +export function getRewardActivity(id) {
  39 + return request({
  40 + url: '/promotion/reward-activity/get?id=' + id,
  41 + method: 'get'
  42 + })
  43 +}
  44 +
  45 +// 获得满减送活动分页
  46 +export function getRewardActivityPage(query) {
  47 + return request({
  48 + url: '/promotion/reward-activity/page',
  49 + method: 'get',
  50 + params: query
  51 + })
  52 +}
yudao-ui-admin/src/utils/constants.js
@@ -278,3 +278,39 @@ export const PromotionProductScopeEnum = { @@ -278,3 +278,39 @@ export const PromotionProductScopeEnum = {
278 name: '指定商品参与' 278 name: '指定商品参与'
279 } 279 }
280 } 280 }
  281 +
  282 +/**
  283 + * 营销的条件类型枚举
  284 + */
  285 +export const PromotionConditionTypeEnum = {
  286 + PRICE: {
  287 + type: 10,
  288 + name: '满 N 元'
  289 + },
  290 + COUNT: {
  291 + type: 20,
  292 + name: '满 N 件'
  293 + }
  294 +}
  295 +
  296 +/**
  297 + * 促销活动的状态枚举
  298 + */
  299 +export const PromotionActivityStatusEnum = {
  300 + WAIT: {
  301 + type: 10,
  302 + name: '未开始'
  303 + },
  304 + RUN: {
  305 + type: 20,
  306 + name: '进行中'
  307 + },
  308 + END: {
  309 + type: 30,
  310 + name: '已结束'
  311 + },
  312 + CLOSE: {
  313 + type: 40,
  314 + name: '已关闭'
  315 + }
  316 +}
yudao-ui-admin/src/utils/dict.js
@@ -63,7 +63,11 @@ export const DICT_TYPE = { @@ -63,7 +63,11 @@ export const DICT_TYPE = {
63 // ========== MALL - PROMOTION 模块 ========== 63 // ========== MALL - PROMOTION 模块 ==========
64 PROMOTION_DISCOUNT_TYPE: 'promotion_discount_type', // 优惠类型 64 PROMOTION_DISCOUNT_TYPE: 'promotion_discount_type', // 优惠类型
65 PROMOTION_PRODUCT_SCOPE: 'promotion_product_scope', // 营销的商品范围 65 PROMOTION_PRODUCT_SCOPE: 'promotion_product_scope', // 营销的商品范围
66 - COUPON_TEMPLATE_VALIDITY_TYPE: 'coupon_template_validity_type', // 优惠劵模板的有限期类型 66 + PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE: 'promotion_coupon_template_validity_type', // 优惠劵模板的有限期类型
  67 + PROMOTION_COUPON_STATUS: 'promotion_coupon_status', // 优惠劵的状态
  68 + PROMOTION_COUPON_TAKE_TYPE: 'promotion_coupon_take_type', // 优惠劵的领取方式
  69 + PROMOTION_ACTIVITY_STATUS: 'promotion_activity_status', // 优惠活动的状态
  70 + PROMOTION_CONDITION_TYPE: 'promotion_condition_type', // 营销的条件类型枚举
67 } 71 }
68 72
69 /** 73 /**
yudao-ui-admin/src/views/mall/CouponTemplete/index.vue deleted
1 -<template>  
2 - <div class="app-container">  
3 -  
4 - <!-- 搜索工作栏 -->  
5 - <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">  
6 - <el-form-item label="优惠券类" prop="type">  
7 - <el-select v-model="queryParams.type" placeholder="请选择优惠券类型 reward-满减 discount-折扣 random-随机" clearable size="small">  
8 - <el-option label="请选择字典生成" value="" />  
9 - </el-select>  
10 - </el-form-item>  
11 - <el-form-item label="优惠券名称" prop="name">  
12 - <el-input v-model="queryParams.name" placeholder="请输入优惠券名称" clearable @keyup.enter.native="handleQuery"/>  
13 - </el-form-item>  
14 -  
15 - <el-form-item label="状态" prop="status">  
16 - <el-select v-model="queryParams.status" placeholder="请选择状态(1进行中2已结束-1已关闭)" clearable size="small">  
17 - <el-option label="请选择字典生成" value="" />  
18 - </el-select>  
19 - </el-form-item>  
20 - <el-form-item label="有效日期结束时间" prop="endTime">  
21 - <el-date-picker v-model="queryParams.endTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"  
22 - range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />  
23 - </el-form-item>  
24 -  
25 - <el-form-item>  
26 - <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>  
27 - <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>  
28 - </el-form-item>  
29 - </el-form>  
30 -  
31 - <!-- 操作工具栏 -->  
32 - <el-row :gutter="10" class="mb8">  
33 - <el-col :span="1.5">  
34 - <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"  
35 - v-hasPermi="['CouponTemplete::create']">新增</el-button>  
36 - </el-col>  
37 - <el-col :span="1.5">  
38 - <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"  
39 - v-hasPermi="['CouponTemplete::export']">导出</el-button>  
40 - </el-col>  
41 - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>  
42 - </el-row>  
43 -  
44 - <!-- 列表 -->  
45 - <el-table v-loading="loading" :data="list">  
46 -  
47 - <!-- todo 优惠券类型-->  
48 - <el-table-column label="优惠券类型" align="center" prop="type" />  
49 - <el-table-column label="优惠券名称" align="center" prop="name" />  
50 - <el-table-column label="优惠券图片" align="center" prop="image" />  
51 - <el-table-column label="发放数量" align="center" prop="count" />  
52 - <el-table-column label="已领取数量" align="center" prop="leadCount" />  
53 - <el-table-column label="已使用数量" align="center" prop="usedCount" />  
54 -<!-- todo 适用商品类型-->  
55 -<!-- <el-table-column label="适用商品类型" align="center" prop="goodsType" />-->  
56 - <!-- todo 使用门槛0-无门槛 1-有门槛-->  
57 -  
58 - <el-table-column label="使用门槛" align="center" prop="hasUseLimit" />  
59 -<!-- <el-table-column label="满多少元使用 0代表无限制" align="center" prop="atLeast" />-->  
60 - <!-- todo 发放面额 折扣-->  
61 - <el-table-column label="优惠金额/折扣" align="center" prop="money" />  
62 -<!-- <el-table-column label="1 =< 折扣 <= 9.9 当type为discount时需要添加" align="center" prop="discount" />-->  
63 -<!-- <el-table-column label="最多折扣金额 当type为discount时可选择性添加" align="center" prop="discountLimit" />-->  
64 -<!-- <el-table-column label="最低金额 当type为radom时需要添加" align="center" prop="minMoney" />-->  
65 -<!-- <el-table-column label="最大金额 当type为radom时需要添加" align="center" prop="maxMoney" />-->  
66 - <!-- todo 1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期 -->  
67 - <el-table-column label="有效期限" align="center" prop="validityType" />  
68 -<!-- <el-table-column label="使用开始日期 过期类型1时必填" align="center" prop="startUseTime" width="180">-->  
69 -<!-- <template slot-scope="scope">-->  
70 -<!-- <span>{{ parseTime(scope.row.startUseTime) }}</span>-->  
71 -<!-- </template>-->  
72 -<!-- </el-table-column>-->  
73 -<!-- <el-table-column label="使用结束日期 过期类型1时必填" align="center" prop="endUseTime" width="180">-->  
74 -<!-- <template slot-scope="scope">-->  
75 -<!-- <span>{{ parseTime(scope.row.endUseTime) }}</span>-->  
76 -<!-- </template>-->  
77 -<!-- </el-table-column>-->  
78 -<!-- <el-table-column label="有效日期结束时间" align="center" prop="endTime" width="180">-->  
79 -<!-- <template slot-scope="scope">-->  
80 -<!-- <span>{{ parseTime(scope.row.endTime) }}</span>-->  
81 -<!-- </template>-->  
82 -<!-- </el-table-column>-->  
83 -<!-- <el-table-column label="当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效" align="center" prop="fixedTerm" />-->  
84 -<!-- <el-table-column label="是否无限制0-否 1是" align="center" prop="whetherLimitless" />-->  
85 - <el-table-column label="领取上限" align="center" prop="maxFetch" />  
86 - <!-- todo 0-不限制 1- 优惠券仅原价购买商品时可用-->  
87 - <el-table-column label="优惠叠加" align="center" prop="whetherForbidPreference" />  
88 - <el-table-column label="是否显示" align="center" prop="whetherShow" />  
89 - <el-table-column label="订单的优惠总金额" align="center" prop="discountOrderMoney" />  
90 - <el-table-column label="用券总成交额" align="center" prop="orderMoney" />  
91 - <el-table-column label="是否禁止发放" align="center" prop="whetherForbidden" />  
92 - <el-table-column label="使用优惠券购买的商品数量" align="center" prop="orderGoodsNum" />  
93 - <el-table-column label="状态" align="center" prop="status" />  
94 -  
95 - <el-table-column label="备注" align="center" prop="couponNameRemark" />  
96 -  
97 - <el-table-column label="操作" align="center" class-name="small-padding fixed-width">  
98 -  
99 - <template #scope>  
100 - <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"  
101 - v-hasPermi="['CouponTemplete::update']">修改</el-button>  
102 - <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"  
103 - v-hasPermi="['CouponTemplete::delete']">删除</el-button>  
104 - </template>  
105 - </el-table-column>  
106 - </el-table>  
107 - <!-- 分页组件 -->  
108 - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"  
109 - @pagination="getList"/>  
110 -  
111 - <!-- 对话框(添加 / 修改) -->  
112 - <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>  
113 - <el-form ref="form" :model="form" :rules="rules" label-width="150px">  
114 - <el-form-item label="优惠券类型" prop="type">  
115 - <el-select v-model="form.type" placeholder="请选择优惠券类型 reward-满减 discount-折扣 random-随机">  
116 - <el-option label="请选择字典生成" value="" />  
117 - </el-select>  
118 - </el-form-item>  
119 - <el-form-item label="优惠券名称" prop="name">  
120 - <el-input v-model="form.name" placeholder="请输入优惠券名称" />  
121 - </el-form-item>  
122 - <el-form-item label="名称备注" prop="couponNameRemark">  
123 - <el-input v-model="form.couponNameRemark" placeholder="请输入名称备注" />  
124 - </el-form-item>  
125 - <el-form-item label="发放数量" prop="count">  
126 - <el-input v-model="form.count" placeholder="请输入发放数量" />  
127 - </el-form-item>  
128 - <el-form-item label="适用商品类型" prop="goodsType">  
129 - <el-radio-group v-model="form.goodsType">  
130 - <el-radio label="1">请选择字典生成</el-radio>  
131 - </el-radio-group>  
132 - </el-form-item>  
133 - <!-- todo 请输入适用商品id-->  
134 - <el-form-item label="适用商品id" prop="productIds">  
135 - <el-input v-model="form.productIds" placeholder="请输入适用商品id" />  
136 - </el-form-item>  
137 - <el-form-item label="使用门槛" prop="hasUseLimit">  
138 - <el-radio-group v-model="form.hasUseLimit">  
139 - <el-radio label="1">请选择字典生成</el-radio>  
140 - </el-radio-group>  
141 - </el-form-item>  
142 - <el-form-item label="满多少元使用" prop="atLeast">  
143 - <el-input v-model="form.atLeast" placeholder="请输入满多少元使用 0代表无限制" />  
144 - </el-form-item>  
145 - <el-form-item label="发放面额" prop="money">  
146 - <el-input v-model="form.money" placeholder="请输入发放面额 当type为reward时需要添加" />  
147 - </el-form-item>  
148 - <el-form-item label="1 =< 折扣 <= 9.9" prop="discount">  
149 - <el-input v-model="form.discount" placeholder="请输入1 =< 折扣 <= 9.9 当type为discount时需要添加" />  
150 - </el-form-item>  
151 - <el-form-item label="最多折扣金额" prop="discountLimit">  
152 - <el-input v-model="form.discountLimit" placeholder="请输入最多折扣金额 当type为discount时可选择性添加" />  
153 - </el-form-item>  
154 - <el-form-item label="最低金额" prop="minMoney">  
155 - <el-input v-model="form.minMoney" placeholder="请输入最低金额 当type为radom时需要添加" />  
156 - </el-form-item>  
157 - <el-form-item label="最大金额" prop="maxMoney">  
158 - <el-input v-model="form.maxMoney" placeholder="请输入最大金额 当type为radom时需要添加" />  
159 - </el-form-item>  
160 - <el-form-item label="过期类型" prop="validityType">  
161 - <el-radio-group v-model="form.validityType">  
162 - <el-radio label="1">请选择字典生成</el-radio>  
163 - </el-radio-group>  
164 - </el-form-item>  
165 - <el-form-item label="使用开始日期 过期类型1时必填" prop="startUseTime">  
166 - <el-date-picker clearable v-model="form.startUseTime" type="date" value-format="timestamp" placeholder="选择使用开始日期 过期类型1时必填" />  
167 - </el-form-item>  
168 - <el-form-item label="使用结束日期 过期类型1时必填" prop="endUseTime">  
169 - <el-date-picker clearable v-model="form.endUseTime" type="date" value-format="timestamp" placeholder="选择使用结束日期 过期类型1时必填" />  
170 - </el-form-item>  
171 - <el-form-item label="当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效" prop="fixedTerm">  
172 - <el-input v-model="form.fixedTerm" placeholder="请输入当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效" />  
173 - </el-form-item>  
174 - <el-form-item label="是否无限制0-否 1是" prop="whetherLimitless">  
175 - <el-radio-group v-model="form.whetherLimitless">  
176 - <el-radio label="1">请选择字典生成</el-radio>  
177 - </el-radio-group>  
178 - </el-form-item>  
179 - <el-form-item label="每人最大领取个数" prop="maxFetch">  
180 - <el-input v-model="form.maxFetch" placeholder="请输入每人最大领取个数" />  
181 - </el-form-item>  
182 - <el-form-item label="是否开启过期提醒0-不开启 1-开启" prop="whetherExpireNotice">  
183 - <el-radio-group v-model="form.whetherExpireNotice">  
184 - <el-radio label="1">请选择字典生成</el-radio>  
185 - </el-radio-group>  
186 - </el-form-item>  
187 - <el-form-item label="过期前N天提醒" prop="expireNoticeFixedTerm">  
188 - <el-input v-model="form.expireNoticeFixedTerm" placeholder="请输入过期前N天提醒" />  
189 - </el-form-item>  
190 - <el-form-item label="优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用" prop="whetherForbidPreference">  
191 - <el-radio-group v-model="form.whetherForbidPreference">  
192 - <el-radio label="1">请选择字典生成</el-radio>  
193 - </el-radio-group>  
194 - </el-form-item>  
195 - <el-form-item label="是否显示" prop="whetherShow">  
196 - <el-input v-model="form.whetherShow" placeholder="请输入是否显示" />  
197 - </el-form-item>  
198 - <el-form-item label="订单的优惠总金额" prop="discountOrderMoney">  
199 - <el-input v-model="form.discountOrderMoney" placeholder="请输入订单的优惠总金额" />  
200 - </el-form-item>  
201 - <el-form-item label="用券总成交额" prop="orderMoney">  
202 - <el-input v-model="form.orderMoney" placeholder="请输入用券总成交额" />  
203 - </el-form-item>  
204 - <el-form-item label="是否禁止发放0-否 1-是" prop="whetherForbidden">  
205 - <el-radio-group v-model="form.whetherForbidden">  
206 - <el-radio label="1">请选择字典生成</el-radio>  
207 - </el-radio-group>  
208 - </el-form-item>  
209 - <el-form-item label="使用优惠券购买的商品数量" prop="orderGoodsNum">  
210 - <el-input v-model="form.orderGoodsNum" placeholder="请输入使用优惠券购买的商品数量" />  
211 - </el-form-item>  
212 - <el-form-item label="状态" prop="status">  
213 - <el-radio-group v-model="form.status">  
214 - <el-radio label="1">请选择字典生成</el-radio>  
215 - </el-radio-group>  
216 - </el-form-item>  
217 - <el-form-item label="有效日期结束时间" prop="endTime">  
218 - <el-date-picker clearable v-model="form.endTime" type="date" value-format="timestamp" placeholder="选择有效日期结束时间" />  
219 - </el-form-item>  
220 - </el-form>  
221 - <div slot="footer" class="dialog-footer">  
222 - <el-button type="primary" @click="submitForm">确 定</el-button>  
223 - <el-button @click="cancel">取 消</el-button>  
224 - </div>  
225 - </el-dialog>  
226 - </div>  
227 -</template>  
228 -  
229 -<script>  
230 -import { create, update, deleteCouponTemplete, get, getPage, exportExcel } from "@/api/mall/CouponTemplete/CouponTemplete.js";  
231 -import {getDictDatas} from "@/utils/dict";  
232 -  
233 -export default {  
234 - name: "",  
235 - components: {  
236 - },  
237 - data() {  
238 - return {  
239 - // 遮罩层  
240 - loading: true,  
241 - // 导出遮罩层  
242 - exportLoading: false,  
243 - // 显示搜索条件  
244 - showSearch: true,  
245 - // 总条数  
246 - total: 0,  
247 - // 优惠券模板列表  
248 - list: [],  
249 - // 弹出层标题  
250 - title: "",  
251 - // 是否显示弹出层  
252 - open: false,  
253 - // 查询参数  
254 - queryParams: {  
255 - pageNo: 1,  
256 - pageSize: 10,  
257 - type: null,  
258 - name: null,  
259 - couponNameRemark: null,  
260 - image: null,  
261 - count: null,  
262 - leadCount: null,  
263 - usedCount: null,  
264 - goodsType: null,  
265 - productIds: null,  
266 - hasUseLimit: null,  
267 - atLeast: null,  
268 - money: null,  
269 - discount: null,  
270 - discountLimit: null,  
271 - minMoney: null,  
272 - maxMoney: null,  
273 - validityType: null,  
274 - startUseTime: [],  
275 - endUseTime: [],  
276 - fixedTerm: null,  
277 - whetherLimitless: null,  
278 - maxFetch: null,  
279 - whetherExpireNotice: null,  
280 - expireNoticeFixedTerm: null,  
281 - whetherForbidPreference: null,  
282 - whetherShow: null,  
283 - discountOrderMoney: null,  
284 - orderMoney: null,  
285 - whetherForbidden: null,  
286 - orderGoodsNum: null,  
287 - status: null,  
288 - endTime: [],  
289 - createTime: [],  
290 - },  
291 - //数据字典  
292 - datas:getDictDatas(),  
293 -  
294 - // 表单参数  
295 - form: {},  
296 - // 表单校验  
297 - rules: {  
298 - type: [{ required: true, message: "优惠券类型 reward-满减 discount-折扣 random-随机不能为空", trigger: "change" }],  
299 - name: [{ required: true, message: "优惠券名称不能为空", trigger: "blur" }],  
300 - count: [{ required: true, message: "发放数量不能为空", trigger: "blur" }],  
301 - leadCount: [{ required: true, message: "已领取数量不能为空", trigger: "blur" }],  
302 - usedCount: [{ required: true, message: "已使用数量不能为空", trigger: "blur" }],  
303 - goodsType: [{ required: true, message: "适用商品类型1-全部商品可用;2-指定商品可用;3-指定商品不可用不能为空", trigger: "blur" }],  
304 - hasUseLimit: [{ required: true, message: "使用门槛0-无门槛 1-有门槛不能为空", trigger: "blur" }],  
305 - atLeast: [{ required: true, message: "满多少元使用 0代表无限制不能为空", trigger: "blur" }],  
306 - money: [{ required: true, message: "发放面额 当type为reward时需要添加不能为空", trigger: "blur" }],  
307 - discount: [{ required: true, message: "1 =< 折扣 <= 9.9 当type为discount时需要添加不能为空", trigger: "blur" }],  
308 - discountLimit: [{ required: true, message: "最多折扣金额 当type为discount时可选择性添加不能为空", trigger: "blur" }],  
309 - minMoney: [{ required: true, message: "最低金额 当type为radom时需要添加不能为空", trigger: "blur" }],  
310 - maxMoney: [{ required: true, message: "最大金额 当type为radom时需要添加不能为空", trigger: "blur" }],  
311 - validityType: [{ required: true, message: "过期类型1-时间范围过期 2-领取之日固定日期后过期 3-领取次日固定日期后过期不能为空", trigger: "blur" }],  
312 - fixedTerm: [{ required: true, message: "当validity_type为2或者3时需要添加 领取之日起或者次日N天内有效不能为空", trigger: "blur" }],  
313 - whetherLimitless: [{ required: true, message: "是否无限制0-否 1是不能为空", trigger: "blur" }],  
314 - maxFetch: [{ required: true, message: "每人最大领取个数不能为空", trigger: "blur" }],  
315 - whetherExpireNotice: [{ required: true, message: "是否开启过期提醒0-不开启 1-开启不能为空", trigger: "blur" }],  
316 - expireNoticeFixedTerm: [{ required: true, message: "过期前N天提醒不能为空", trigger: "blur" }],  
317 - whetherForbidPreference: [{ required: true, message: "优惠叠加 0-不限制 1- 优惠券仅原价购买商品时可用不能为空", trigger: "blur" }],  
318 - whetherShow: [{ required: true, message: "是否显示不能为空", trigger: "blur" }],  
319 - discountOrderMoney: [{ required: true, message: "订单的优惠总金额不能为空", trigger: "blur" }],  
320 - orderMoney: [{ required: true, message: "用券总成交额不能为空", trigger: "blur" }],  
321 - whetherForbidden: [{ required: true, message: "是否禁止发放0-否 1-是不能为空", trigger: "blur" }],  
322 - orderGoodsNum: [{ required: true, message: "使用优惠券购买的商品数量不能为空", trigger: "blur" }],  
323 - status: [{ required: true, message: "状态(1进行中2已结束-1已关闭)不能为空", trigger: "blur" }],  
324 - }  
325 - };  
326 - },  
327 - created() {  
328 - this.getList();  
329 - },  
330 - methods: {  
331 - /** 查询列表 */  
332 - getList() {  
333 - this.loading = true;  
334 - // 执行查询  
335 - getPage(this.queryParams).then(response => {  
336 - this.list = response.data.list;  
337 - this.total = response.data.total;  
338 - this.loading = false;  
339 - });  
340 - },  
341 - /** 取消按钮 */  
342 - cancel() {  
343 - this.open = false;  
344 - this.reset();  
345 - },  
346 - /** 表单重置 */  
347 - reset() {  
348 - this.form = {  
349 - id: undefined,  
350 - type: undefined,  
351 - name: undefined,  
352 - couponNameRemark: undefined,  
353 - image: undefined,  
354 - count: undefined,  
355 - leadCount: undefined,  
356 - usedCount: undefined,  
357 - goodsType: undefined,  
358 - productIds: undefined,  
359 - hasUseLimit: undefined,  
360 - atLeast: undefined,  
361 - money: undefined,  
362 - discount: undefined,  
363 - discountLimit: undefined,  
364 - minMoney: undefined,  
365 - maxMoney: undefined,  
366 - validityType: undefined,  
367 - startUseTime: undefined,  
368 - endUseTime: undefined,  
369 - fixedTerm: undefined,  
370 - whetherLimitless: undefined,  
371 - maxFetch: undefined,  
372 - whetherExpireNotice: undefined,  
373 - expireNoticeFixedTerm: undefined,  
374 - whetherForbidPreference: undefined,  
375 - whetherShow: undefined,  
376 - discountOrderMoney: undefined,  
377 - orderMoney: undefined,  
378 - whetherForbidden: undefined,  
379 - orderGoodsNum: undefined,  
380 - status: undefined,  
381 - endTime: undefined,  
382 - };  
383 - this.resetForm("form");  
384 - },  
385 - /** 搜索按钮操作 */  
386 - handleQuery() {  
387 - this.queryParams.pageNo = 1;  
388 - this.getList();  
389 - },  
390 - /** 重置按钮操作 */  
391 - resetQuery() {  
392 - this.resetForm("queryForm");  
393 - this.handleQuery();  
394 - },  
395 - /** 新增按钮操作 */  
396 - handleAdd() {  
397 - this.reset();  
398 - this.open = true;  
399 - this.title = "添加优惠券模板";  
400 - },  
401 - /** 修改按钮操作 */  
402 - handleUpdate(row) {  
403 - this.reset();  
404 - const id = row.id;  
405 - get(id).then(response => {  
406 - this.form = response.data;  
407 - this.open = true;  
408 - this.title = "修改优惠券模板";  
409 - });  
410 - },  
411 - /** 提交按钮 */  
412 - submitForm() {  
413 - this.$refs["form"].validate(valid => {  
414 - if (!valid) {  
415 - return;  
416 - }  
417 - // 修改的提交  
418 - if (this.form.id != null) {  
419 - update(this.form).then(response => {  
420 - this.$modal.msgSuccess("修改成功");  
421 - this.open = false;  
422 - this.getList();  
423 - });  
424 - return;  
425 - }  
426 - // 添加的提交  
427 - create(this.form).then(response => {  
428 - this.$modal.msgSuccess("新增成功");  
429 - this.open = false;  
430 - this.getList();  
431 - });  
432 - });  
433 - },  
434 - /** 删除按钮操作 */  
435 - handleDelete(row) {  
436 - const id = row.id;  
437 - this.$modal.confirm('是否确认删除优惠券模板编号为"' + id + '"的数据项?').then(function() {  
438 - return deleteCouponTemplete(id);  
439 - }).then(() => {  
440 - this.getList();  
441 - this.$modal.msgSuccess("删除成功");  
442 - }).catch(() => {});  
443 - },  
444 - /** 导出按钮操作 */  
445 - handleExport() {  
446 - // 处理查询参数  
447 - let params = {...this.queryParams};  
448 - params.pageNo = undefined;  
449 - params.pageSize = undefined;  
450 - this.$modal.confirm('是否确认导出所有优惠券模板数据项?').then(() => {  
451 - this.exportLoading = true;  
452 - return exportExcel(params);  
453 - }).then(response => {  
454 - this.$download.excel(response, '优惠券模板.xls');  
455 - this.exportLoading = false;  
456 - }).catch(() => {});  
457 - }  
458 - }  
459 -};  
460 -</script>  
yudao-ui-admin/src/views/mall/promotion/coupon/index.vue 0 → 100755
  1 +<template>
  2 + <div class="app-container">
  3 + <!-- 搜索工作栏 -->
  4 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  5 + <el-form-item label="会员昵称" prop="nickname">
  6 + <el-input v-model="queryParams.nickname" placeholder="请输入会员昵称" clearable @keyup.enter.native="handleQuery"/>
  7 + </el-form-item>
  8 + <el-form-item label="创建时间" prop="createTime">
  9 + <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
  10 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
  11 + </el-form-item>
  12 + <el-form-item>
  13 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  14 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  15 + </el-form-item>
  16 + </el-form>
  17 +
  18 + <!-- 操作工具栏 -->
  19 + <el-row :gutter="10" class="mb8">
  20 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  21 + </el-row>
  22 +
  23 + <!-- Tab 选项:真正的内容在 Lab -->
  24 + <el-tabs v-model="activeTab" type="card" @tab-click="tabClick" style="margin-top: -40px;">
  25 + <el-tab-pane v-for="tab in statusTabs" :key="tab.value" :label="tab.label" :name="tab.value" />
  26 + </el-tabs>
  27 +
  28 + <!-- 列表 -->
  29 + <el-table v-loading="loading" :data="list">
  30 + <el-table-column label="会员信息" align="center" prop="nickname" /> <!-- TODO 芋艿:以后支持头像,支持跳转 -->
  31 + <el-table-column label="优惠劵" align="center" prop="name" />
  32 + <el-table-column label="优惠券类型" align="center" prop="discountType">
  33 + <template slot-scope="scope">
  34 + <dict-tag :type="DICT_TYPE.PROMOTION_DISCOUNT_TYPE" :value="scope.row.discountType" />
  35 + </template>
  36 + </el-table-column>
  37 + <el-table-column label="领取方式" align="center" prop="takeType">
  38 + <template slot-scope="scope">
  39 + <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_TAKE_TYPE" :value="scope.row.takeType" />
  40 + </template>
  41 + </el-table-column>
  42 + <el-table-column label="状态" align="center" prop="status">
  43 + <template slot-scope="scope">
  44 + <dict-tag :type="DICT_TYPE.PROMOTION_COUPON_STATUS" :value="scope.row.status" />
  45 + </template>
  46 + </el-table-column>
  47 + <el-table-column label="领取时间" align="center" prop="createTime" width="180">
  48 + <template slot-scope="scope">
  49 + <span>{{ parseTime(scope.row.createTime) }}</span>
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column label="使用时间" align="center" prop="useTime" width="180">
  53 + <template slot-scope="scope">
  54 + <span>{{ parseTime(scope.row.useTime) }}</span>
  55 + </template>
  56 + </el-table-column>
  57 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  58 + <template slot-scope="scope">
  59 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  60 + v-hasPermi="['promotion:coupon:delete']">回收</el-button>
  61 + </template>
  62 + </el-table-column>
  63 + </el-table>
  64 + <!-- 分页组件 -->
  65 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  66 + @pagination="getList"/>
  67 + </div>
  68 +</template>
  69 +
  70 +<script>
  71 +import { deleteCoupon, getCouponPage } from "@/api/mall/promotion/coupon";
  72 +import { DICT_TYPE, getDictDatas} from "@/utils/dict";
  73 +
  74 +export default {
  75 + name: "Coupon",
  76 + components: {
  77 + },
  78 + data() {
  79 + return {
  80 + // 遮罩层
  81 + loading: true,
  82 + // 导出遮罩层
  83 + exportLoading: false,
  84 + // 显示搜索条件
  85 + showSearch: true,
  86 + // 总条数
  87 + total: 0,
  88 + // 优惠劵列表
  89 + list: [],
  90 + // 弹出层标题
  91 + title: "",
  92 + // 是否显示弹出层
  93 + open: false,
  94 + // 查询参数
  95 + queryParams: {
  96 + pageNo: 1,
  97 + pageSize: 10,
  98 + createTime: [],
  99 + status: undefined,
  100 + },
  101 + // Tab 筛选
  102 + activeTab: 'all',
  103 + statusTabs: [{
  104 + label: '全部',
  105 + value: 'all'
  106 + }],
  107 + };
  108 + },
  109 + created() {
  110 + this.getList();
  111 + // 设置 statuses 过滤
  112 + for (const dict of getDictDatas(DICT_TYPE.PROMOTION_COUPON_STATUS)) {
  113 + this.statusTabs.push({
  114 + label: dict.label,
  115 + value: dict.value
  116 + })
  117 + }
  118 + },
  119 + methods: {
  120 + /** 查询列表 */
  121 + getList() {
  122 + this.loading = true;
  123 + // 执行查询
  124 + getCouponPage(this.queryParams).then(response => {
  125 + this.list = response.data.list;
  126 + this.total = response.data.total;
  127 + this.loading = false;
  128 + });
  129 + },
  130 + /** 取消按钮 */
  131 + cancel() {
  132 + this.open = false;
  133 + this.reset();
  134 + },
  135 + /** 搜索按钮操作 */
  136 + handleQuery() {
  137 + this.queryParams.pageNo = 1;
  138 + this.getList();
  139 + },
  140 + /** 重置按钮操作 */
  141 + resetQuery() {
  142 + this.resetForm("queryForm");
  143 + this.handleQuery();
  144 + },
  145 + /** 删除按钮操作 */
  146 + handleDelete(row) {
  147 + const id = row.id;
  148 + this.$modal.confirm('回收将会收回会员领取的待使用的优惠券,已使用的将无法回收,确定要回收所选优惠券吗?').then(function() {
  149 + return deleteCoupon(id);
  150 + }).then(() => {
  151 + this.getList();
  152 + this.$modal.msgSuccess("回收成功");
  153 + }).catch(() => {});
  154 + },
  155 + /** tab 切换 */
  156 + tabClick(tab) {
  157 + this.queryParams.status = tab.name === 'all' ? undefined : tab.name;
  158 + this.getList();
  159 + }
  160 + }
  161 +};
  162 +</script>
yudao-ui-admin/src/views/promotion/couponTemplate/index.vue renamed to yudao-ui-admin/src/views/mall/promotion/couponTemplate/index.vue
@@ -33,6 +33,9 @@ @@ -33,6 +33,9 @@
33 <el-col :span="1.5"> 33 <el-col :span="1.5">
34 <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" 34 <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
35 v-hasPermi="['promotion:coupon-template:create']">新增</el-button> 35 v-hasPermi="['promotion:coupon-template:create']">新增</el-button>
  36 + <el-button type="info" plain icon="el-icon-s-operation" size="mini"
  37 + @click="() => this.$router.push('/promotion/coupon')"
  38 + v-hasPermi="['promotion:coupon:query']">会员优惠劵</el-button>
36 </el-col> 39 </el-col>
37 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> 40 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
38 </el-row> 41 </el-row>
@@ -52,7 +55,7 @@ @@ -52,7 +55,7 @@
52 <el-table-column label="有效期限" align="center" prop="validityType" width="180" :formatter="validityTypeFormat" /> 55 <el-table-column label="有效期限" align="center" prop="validityType" width="180" :formatter="validityTypeFormat" />
53 <el-table-column label="状态" align="center" prop="status"> 56 <el-table-column label="状态" align="center" prop="status">
54 <template slot-scope="scope"> 57 <template slot-scope="scope">
55 - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> 58 + <el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)"/>
56 </template> 59 </template>
57 </el-table-column> 60 </el-table-column>
58 <el-table-column label="创建时间" align="center" prop="createTime" width="180"> 61 <el-table-column label="创建时间" align="center" prop="createTime" width="180">
@@ -108,7 +111,7 @@ @@ -108,7 +111,7 @@
108 </el-radio-group> 111 </el-radio-group>
109 </el-form-item> 112 </el-form-item>
110 <el-form-item v-if="form.takeType === 1" label="发放数量" prop="totalCount"> 113 <el-form-item v-if="form.takeType === 1" label="发放数量" prop="totalCount">
111 - <el-input-number v-model="form.usePrice" placeholder="发放数量,没有之后不能领取或发放,-1 为不限制" 114 + <el-input-number v-model="form.totalCount" placeholder="发放数量,没有之后不能领取或发放,-1 为不限制"
112 style="width: 400px" :precision="0" :min="-1" /> 张 115 style="width: 400px" :precision="0" :min="-1" /> 张
113 </el-form-item> 116 </el-form-item>
114 <el-form-item v-if="form.takeType === 1" label="每人限领个数" prop="takeLimitCount"> 117 <el-form-item v-if="form.takeType === 1" label="每人限领个数" prop="takeLimitCount">
@@ -117,13 +120,13 @@ @@ -117,13 +120,13 @@
117 </el-form-item> 120 </el-form-item>
118 <el-form-item label="有效期类型" prop="validityType"> 121 <el-form-item label="有效期类型" prop="validityType">
119 <el-radio-group v-model="form.validityType"> 122 <el-radio-group v-model="form.validityType">
120 - <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.COUPON_TEMPLATE_VALIDITY_TYPE)" 123 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE)"
121 :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio> 124 :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
122 </el-radio-group> 125 </el-radio-group>
123 </el-form-item> 126 </el-form-item>
124 <el-form-item v-if="form.validityType === CouponTemplateValidityTypeEnum.DATE.type" label="固定日期" prop="validTimes"> 127 <el-form-item v-if="form.validityType === CouponTemplateValidityTypeEnum.DATE.type" label="固定日期" prop="validTimes">
125 - <el-date-picker v-model="queryParams.validTimes" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"  
126 - range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" /> 128 + <el-date-picker v-model="form.validTimes" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
  129 + :default-time="['00:00:00', '23:59:59']" />
127 </el-form-item> 130 </el-form-item>
128 <el-form-item v-if="form.validityType === CouponTemplateValidityTypeEnum.TERM.type" label="领取日期" prop="fixedStartTerm"> 131 <el-form-item v-if="form.validityType === CouponTemplateValidityTypeEnum.TERM.type" label="领取日期" prop="fixedStartTerm">
129 第 <el-input-number v-model="form.fixedStartTerm" placeholder="0 为今天生效" 132 第 <el-input-number v-model="form.fixedStartTerm" placeholder="0 为今天生效"
@@ -138,7 +141,13 @@ @@ -138,7 +141,13 @@
138 </el-radio-group> 141 </el-radio-group>
139 </el-form-item> 142 </el-form-item>
140 <el-form-item v-if="form.productScope === PromotionProductScopeEnum.SPU.scope" prop="productSpuIds"> 143 <el-form-item v-if="form.productScope === PromotionProductScopeEnum.SPU.scope" prop="productSpuIds">
141 - <el-input v-model="form.productSpuIds" placeholder="请输入商品 SPU 编号的数组" /> 144 + <el-select v-model="form.productSpuIds" placeholder="请选择活动商品" clearable size="small"
  145 + multiple filterable style="width: 400px">
  146 + <el-option v-for="item in productSpus" :key="item.id" :label="item.name" :value="item.id">
  147 + <span style="float: left">{{ item.name }}</span>
  148 + <span style="float: right; color: #8492a6; font-size: 13px">¥{{ (item.minPrice / 100.0).toFixed(2) }}</span>
  149 + </el-option>
  150 + </el-select>
142 </el-form-item> 151 </el-form-item>
143 </el-form> 152 </el-form>
144 <div slot="footer" class="dialog-footer"> 153 <div slot="footer" class="dialog-footer">
@@ -150,8 +159,23 @@ @@ -150,8 +159,23 @@
150 </template> 159 </template>
151 160
152 <script> 161 <script>
153 -import { createCouponTemplate, updateCouponTemplate, deleteCouponTemplate, getCouponTemplate, getCouponTemplatePage } from "@/api/promotion/couponTemplate";  
154 -import { CommonStatusEnum, CouponTemplateValidityTypeEnum, PromotionDiscountTypeEnum, PromotionProductScopeEnum} from "@/utils/constants"; 162 +import {
  163 + createCouponTemplate,
  164 + updateCouponTemplate,
  165 + deleteCouponTemplate,
  166 + getCouponTemplate,
  167 + getCouponTemplatePage,
  168 + updateCouponTemplateStatus
  169 +} from "@/api/mall/promotion/couponTemplate";
  170 +import {
  171 + CommonStatusEnum,
  172 + CouponTemplateValidityTypeEnum,
  173 + PromotionDiscountTypeEnum,
  174 + PromotionProductScopeEnum
  175 +} from "@/utils/constants";
  176 +import { getSpuSimpleList } from "@/api/mall/product/spu";
  177 +import { parseTime } from "@/utils/ruoyi";
  178 +import {changeRoleStatus} from "@/api/system/role";
155 179
156 export default { 180 export default {
157 name: "CouponTemplate", 181 name: "CouponTemplate",
@@ -202,6 +226,8 @@ export default { @@ -202,6 +226,8 @@ export default {
202 productScope: [{ required: true, message: "商品范围不能为空", trigger: "blur" }], 226 productScope: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
203 productSpuIds: [{ required: true, message: "商品范围不能为空", trigger: "blur" }], 227 productSpuIds: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
204 }, 228 },
  229 + // 商品列表
  230 + productSpus: [],
205 // 如下的变量,主要为了 v-if 判断可以使用到 231 // 如下的变量,主要为了 v-if 判断可以使用到
206 PromotionProductScopeEnum: PromotionProductScopeEnum, 232 PromotionProductScopeEnum: PromotionProductScopeEnum,
207 CouponTemplateValidityTypeEnum: CouponTemplateValidityTypeEnum, 233 CouponTemplateValidityTypeEnum: CouponTemplateValidityTypeEnum,
@@ -221,6 +247,10 @@ export default { @@ -221,6 +247,10 @@ export default {
221 this.total = response.data.total; 247 this.total = response.data.total;
222 this.loading = false; 248 this.loading = false;
223 }); 249 });
  250 + // 查询商品列表
  251 + getSpuSimpleList().then(response => {
  252 + this.productSpus = response.data
  253 + })
224 }, 254 },
225 /** 取消按钮 */ 255 /** 取消按钮 */
226 cancel() { 256 cancel() {
@@ -233,7 +263,7 @@ export default { @@ -233,7 +263,7 @@ export default {
233 id: undefined, 263 id: undefined,
234 name: undefined, 264 name: undefined,
235 discountType: PromotionDiscountTypeEnum.PRICE.type, 265 discountType: PromotionDiscountTypeEnum.PRICE.type,
236 - discountPrice: 0, 266 + discountPrice: undefined,
237 discountPercent: undefined, 267 discountPercent: undefined,
238 discountLimitPrice: undefined, 268 discountLimitPrice: undefined,
239 usePrice: undefined, 269 usePrice: undefined,
@@ -274,9 +304,11 @@ export default { @@ -274,9 +304,11 @@ export default {
274 getCouponTemplate(id).then(response => { 304 getCouponTemplate(id).then(response => {
275 this.form = { 305 this.form = {
276 ...response.data, 306 ...response.data,
277 - discountPrice: response.data.discountPrice ? response.data.discountPrice / 100.0 : undefined,  
278 - discountPercent: response.data.discountPercent ? response.data.discountPercent / 10.0 : undefined,  
279 - usePrice: response.data.usePrice ? response.data.usePrice / 100.0 : undefined, 307 + discountPrice: response.data.discountPrice !== undefined ? response.data.discountPrice / 100.0 : undefined,
  308 + discountPercent: response.data.discountPercent !== undefined ? response.data.discountPercent / 10.0 : undefined,
  309 + discountLimitPrice: response.data.discountLimitPrice !== undefined ? response.data.discountLimitPrice / 100.0 : undefined,
  310 + usePrice: response.data.usePrice !== undefined ? response.data.usePrice / 100.0 : undefined,
  311 + validTimes: [response.data.validStartTime, response.data.validEndTime]
280 } 312 }
281 this.open = true; 313 this.open = true;
282 this.title = "修改优惠劵"; 314 this.title = "修改优惠劵";
@@ -291,9 +323,12 @@ export default { @@ -291,9 +323,12 @@ export default {
291 // 金额相关字段的缩放 323 // 金额相关字段的缩放
292 let data = { 324 let data = {
293 ...this.form, 325 ...this.form,
294 - discountPrice: this.form.discountPrice ? this.form.discountPrice * 100 : undefined,  
295 - discountPercent: this.form.discountPercent ? this.form.discountPercent * 10 : undefined,  
296 - usePrice: this.form.usePrice ? this.form.usePrice * 100 : undefined, 326 + discountPrice: this.form.discountPrice !== undefined ? this.form.discountPrice * 100 : undefined,
  327 + discountPercent: this.form.discountPercent !== undefined ? this.form.discountPercent * 10 : undefined,
  328 + discountLimitPrice: this.form.discountLimitPrice !== undefined ? this.form.discountLimitPrice * 100 : undefined,
  329 + usePrice: this.form.usePrice !== undefined ? this.form.usePrice * 100 : undefined,
  330 + validStartTime: this.form.validTimes && this.form.validTimes.length === 2 ? this.form.validTimes[0] : undefined,
  331 + validEndTime: this.form.validTimes && this.form.validTimes.length === 2 ? this.form.validTimes[1] : undefined,
297 } 332 }
298 // 修改的提交 333 // 修改的提交
299 if (this.form.id != null) { 334 if (this.form.id != null) {
@@ -312,6 +347,20 @@ export default { @@ -312,6 +347,20 @@ export default {
312 }); 347 });
313 }); 348 });
314 }, 349 },
  350 + /** 优惠劵模板状态修改 */
  351 + handleStatusChange(row) {
  352 + // 此时,row 已经变成目标状态了,所以可以直接提交请求和提示
  353 + let text = row.status === CommonStatusEnum.ENABLE ? "启用" : "停用";
  354 + this.$modal.confirm('确认要"' + text + '""' + row.name + '"优惠劵吗?').then(function() {
  355 + return updateCouponTemplateStatus(row.id, row.status);
  356 + }).then(() => {
  357 + this.$modal.msgSuccess(text + "成功");
  358 + }).catch(function() {
  359 + // 异常时,需要将 row.status 状态重置回之前的
  360 + row.status = row.status === CommonStatusEnum.ENABLE ? CommonStatusEnum.DISABLE
  361 + : CommonStatusEnum.ENABLE;
  362 + });
  363 + },
315 /** 删除按钮操作 */ 364 /** 删除按钮操作 */
316 handleDelete(row) { 365 handleDelete(row) {
317 const id = row.id; 366 const id = row.id;
yudao-ui-admin/src/views/mall/promotion/discountActivity/index.vue 0 → 100755
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="活动名称" prop="name">
  7 + <el-input v-model="queryParams.name" placeholder="请输入活动名称" clearable @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="活动状态" prop="status">
  10 + <el-select v-model="queryParams.status" placeholder="请选择活动状态" clearable size="small">
  11 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_ACTIVITY_STATUS)"
  12 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  13 + </el-select>
  14 + </el-form-item>
  15 + <el-form-item label="创建时间" prop="createTime">
  16 + <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
  17 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
  18 + </el-form-item>
  19 + <el-form-item>
  20 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  21 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  22 + </el-form-item>
  23 + </el-form>
  24 +
  25 + <!-- 操作工具栏 -->
  26 + <el-row :gutter="10" class="mb8">
  27 + <el-col :span="1.5">
  28 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  29 + v-hasPermi="['promotion:discount-activity:create']">新增</el-button>
  30 + </el-col>
  31 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  32 + </el-row>
  33 +
  34 + <!-- 列表 -->
  35 + <el-table v-loading="loading" :data="list">
  36 + <el-table-column label="活动名称" align="center" prop="name" />
  37 + <el-table-column label="活动时间" align="center" prop="startTime" width="240">
  38 + <template slot-scope="scope">
  39 + <div>开始:{{ parseTime(scope.row.startTime) }}</div>
  40 + <div>结束:{{ parseTime(scope.row.endTime) }}</div>
  41 + </template>
  42 + </el-table-column>
  43 + <el-table-column label="状态" align="center" prop="status">
  44 + <template slot-scope="scope">
  45 + <dict-tag :type="DICT_TYPE.PROMOTION_ACTIVITY_STATUS" :value="scope.row.status" />
  46 + </template>
  47 + </el-table-column>
  48 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  49 + <template slot-scope="scope">
  50 + <span>{{ parseTime(scope.row.createTime) }}</span>
  51 + </template>
  52 + </el-table-column>
  53 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  54 + <template slot-scope="scope">
  55 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  56 + v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type"
  57 + v-hasPermi="['promotion:discount-activity:update']">修改</el-button>
  58 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleClose(scope.row)"
  59 + v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type &&
  60 + scope.row.status !== PromotionActivityStatusEnum.END.type"
  61 + v-hasPermi="['promotion:discount-activity:close']">关闭</el-button>
  62 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  63 + v-if="scope.row.status === PromotionActivityStatusEnum.CLOSE.type"
  64 + v-hasPermi="['promotion:discount-activity:delete']">删除</el-button>
  65 + </template>
  66 + </el-table-column>
  67 + </el-table>
  68 + <!-- 分页组件 -->
  69 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  70 + @pagination="getList"/>
  71 +
  72 + <!-- 对话框(添加 / 修改) -->
  73 + <el-dialog :title="title" :visible.sync="open" width="1000px" v-dialogDrag append-to-body>
  74 + <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  75 + <el-form-item label="活动名称" prop="name">
  76 + <el-input v-model="form.name" placeholder="请输入活动名称" />
  77 + </el-form-item>
  78 + <el-form-item label="备注" prop="remark">
  79 + <el-input type="textarea" v-model="form.remark" placeholder="请输入备注" />
  80 + </el-form-item>
  81 + <el-form-item label="活动时间" prop="startAndEndTime">
  82 + <el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
  83 + value-format="timestamp" placeholder="选择开始时间" style="width: 880px" />
  84 + </el-form-item>
  85 + <el-form-item label="商品选择">
  86 + <el-select v-model="form.skuIds" placeholder="请选择活动商品" clearable size="small"
  87 + multiple filterable style="width: 880px" @change="changeFormSku">
  88 + <el-option v-for="item in productSkus" :key="item.id" :label="item.spuName + ' ' + item.name" :value="item.id">
  89 + <span style="float: left">{{ item.spuName }} &nbsp; {{ item.name}}</span>
  90 + <span style="float: right; color: #8492a6; font-size: 13px">¥{{ (item.price / 100.0).toFixed(2) }}</span>
  91 + </el-option>
  92 + </el-select>
  93 + <el-table v-loading="loading" :data="form.products">
  94 + <el-table-column label="商品名称" align="center" width="200">
  95 + <template slot-scope="scope">
  96 + {{ scope.row.spuName }} &nbsp; {{ scope.row.name}}
  97 + </template>
  98 + </el-table-column>
  99 + <el-table-column label="商品价格" align="center" prop="price">
  100 + <template slot-scope="scope">
  101 + ¥{{ (scope.row.price / 100.0).toFixed(2) }}
  102 + </template>
  103 + </el-table-column>
  104 + <el-table-column label="库存" align="center" prop="stock" />
  105 + <el-table-column label="优惠类型" align="center" property="discountType">
  106 + <template slot-scope="scope">
  107 + <el-select v-model="scope.row.discountType" placeholder="请选择优惠类型">
  108 + <el-option v-for="dict in getDictDatas(DICT_TYPE.PROMOTION_DISCOUNT_TYPE)"
  109 + :key="dict.value" :label="dict.label" :value="parseInt(dict.value)"/>
  110 + </el-select>
  111 + </template>
  112 + </el-table-column>
  113 + <el-table-column label="优惠" align="center" prop="startTime" width="250">
  114 + <template slot-scope="scope">
  115 + <el-form-item v-if="scope.row.discountType === PromotionDiscountTypeEnum.PRICE.type" prop="discountPrice">
  116 + 减 <el-input-number v-model="scope.row.discountPrice" placeholder="请输入优惠金额"
  117 + style="width: 190px" :precision="2" :min="0" :max="scope.row.price / 100.0 - 0.01" /> 元
  118 + </el-form-item>
  119 + <el-form-item v-if="scope.row.discountType === PromotionDiscountTypeEnum.PERCENT.type" prop="discountPercent">
  120 + 打 <el-input-number v-model="scope.row.discountPercent" placeholder="请输入优惠折扣"
  121 + style="width: 190px" :precision="1" :min="1" :max="9.9" /> 折
  122 + </el-form-item>
  123 + </template>
  124 + </el-table-column>
  125 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  126 + <template slot-scope="scope">
  127 + <el-button size="mini" type="text" icon="el-icon-delete" @click="removeFormSku(scope.row.skuId)">删除</el-button>
  128 + </template>
  129 + </el-table-column>
  130 + </el-table>
  131 + </el-form-item>
  132 + </el-form>
  133 + <div slot="footer" class="dialog-footer">
  134 + <el-button type="primary" @click="submitForm">确 定</el-button>
  135 + <el-button @click="cancel">取 消</el-button>
  136 + </div>
  137 + </el-dialog>
  138 + </div>
  139 +</template>
  140 +
  141 +<script>
  142 +import {
  143 + createDiscountActivity,
  144 + updateDiscountActivity,
  145 + deleteDiscountActivity,
  146 + getDiscountActivity,
  147 + getDiscountActivityPage,
  148 + closeDiscountActivity
  149 +} from "@/api/mall/promotion/discountActivity";
  150 +import {
  151 + PromotionActivityStatusEnum, PromotionDiscountTypeEnum,
  152 + PromotionProductScopeEnum
  153 +} from "@/utils/constants";
  154 +import { getSkuOptionList } from "@/api/mall/product/sku";
  155 +import { deepClone } from "@/utils";
  156 +
  157 +export default {
  158 + name: "DiscountActivity",
  159 + components: {
  160 + },
  161 + data() {
  162 + return {
  163 + // 遮罩层
  164 + loading: true,
  165 + // 导出遮罩层
  166 + exportLoading: false,
  167 + // 显示搜索条件
  168 + showSearch: true,
  169 + // 总条数
  170 + total: 0,
  171 + // 限时折扣活动列表
  172 + list: [],
  173 + // 弹出层名称
  174 + title: "",
  175 + // 是否显示弹出层
  176 + open: false,
  177 + // 查询参数
  178 + queryParams: {
  179 + pageNo: 1,
  180 + pageSize: 10,
  181 + name: null,
  182 + status: null,
  183 + createTime: [],
  184 + },
  185 + // 表单参数
  186 + form: {
  187 + skuIds: [], // 选中的 SKU
  188 + products: [], // 商品信息
  189 + },
  190 + // 表单校验
  191 + rules: {
  192 + name: [{ required: true, message: "活动名称不能为空", trigger: "blur" }],
  193 + startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }],
  194 + skuIds: [{ required: true, message: "选择商品不能为空", trigger: "blur" }],
  195 + },
  196 + // 商品 SKU 列表
  197 + productSkus: [],
  198 + // 如下的变量,主要为了 v-if 判断可以使用到
  199 + PromotionProductScopeEnum: PromotionProductScopeEnum,
  200 + PromotionActivityStatusEnum: PromotionActivityStatusEnum,
  201 + PromotionDiscountTypeEnum: PromotionDiscountTypeEnum,
  202 + };
  203 + },
  204 + created() {
  205 + this.getList();
  206 + },
  207 + methods: {
  208 + /** 查询列表 */
  209 + getList() {
  210 + this.loading = true;
  211 + // 执行查询
  212 + getDiscountActivityPage(this.queryParams).then(response => {
  213 + this.list = response.data.list;
  214 + this.total = response.data.total;
  215 + this.loading = false;
  216 + });
  217 + // 获得 SKU 商品列表
  218 + getSkuOptionList().then(response => {
  219 + this.productSkus = response.data;
  220 + });
  221 + },
  222 + /** 取消按钮 */
  223 + cancel() {
  224 + this.open = false;
  225 + this.reset();
  226 + },
  227 + /** 表单重置 */
  228 + reset() {
  229 + this.form = {
  230 + id: undefined,
  231 + name: undefined,
  232 + startAndEndTime: undefined,
  233 + startTime: undefined,
  234 + endTime: undefined,
  235 + remark: undefined,
  236 + skuIds: [],
  237 + products: [],
  238 + };
  239 + this.resetForm("form");
  240 + },
  241 + /** 搜索按钮操作 */
  242 + handleQuery() {
  243 + this.queryParams.pageNo = 1;
  244 + this.getList();
  245 + },
  246 + /** 重置按钮操作 */
  247 + resetQuery() {
  248 + this.resetForm("queryForm");
  249 + this.handleQuery();
  250 + },
  251 + /** 新增按钮操作 */
  252 + handleAdd() {
  253 + this.reset();
  254 + this.open = true;
  255 + this.title = "添加限时折扣活动";
  256 + },
  257 + /** 修改按钮操作 */
  258 + handleUpdate(row) {
  259 + this.reset();
  260 + const id = row.id;
  261 + getDiscountActivity(id).then(response => {
  262 + this.form = response.data;
  263 + // 修改数据
  264 + this.form.startAndEndTime = [response.data.startTime, response.data.endTime];
  265 + this.form.skuIds = response.data.products.map(item => item.skuId);
  266 + this.form.products.forEach(product => {
  267 + // 获得对应的 SKU 信息
  268 + const sku = this.productSkus.find(item => item.id === product.skuId);
  269 + if (!sku) {
  270 + return;
  271 + }
  272 + // 设置商品信息
  273 + product.name = sku.name;
  274 + product.spuName = sku.spuName;
  275 + product.price = sku.price;
  276 + product.stock = sku.stock;
  277 + product.discountPrice = product.discountPrice !== undefined ? product.discountPrice / 100.0 : undefined;
  278 + product.discountPercent = product.discountPercent !== undefined ? product.discountPercent / 10.0 : undefined;
  279 + });
  280 + // 打开弹窗
  281 + this.open = true;
  282 + this.title = "修改限时折扣活动";
  283 + });
  284 + },
  285 + /** 提交按钮 */
  286 + submitForm() {
  287 + this.$refs["form"].validate(valid => {
  288 + if (!valid) {
  289 + return;
  290 + }
  291 + // 处理数据
  292 + const data = deepClone(this.form); // 必须深拷贝,不然后面的 products 操作会有影响
  293 + data.startTime = this.form.startAndEndTime[0];
  294 + data.endTime = this.form.startAndEndTime[1];
  295 + data.products.forEach(product => {
  296 + product.discountPrice = product.discountPrice !== undefined ? product.discountPrice * 100 : undefined;
  297 + product.discountPercent = product.discountPercent !== undefined ? product.discountPercent * 10 : undefined;
  298 + });
  299 + if (!valid) {
  300 + return;
  301 + }
  302 +
  303 + // 修改的提交
  304 + if (this.form.id != null) {
  305 + updateDiscountActivity(data).then(response => {
  306 + this.$modal.msgSuccess("修改成功");
  307 + this.open = false;
  308 + this.getList();
  309 + });
  310 + return;
  311 + }
  312 + // 添加的提交
  313 + createDiscountActivity(data).then(response => {
  314 + this.$modal.msgSuccess("新增成功");
  315 + this.open = false;
  316 + this.getList();
  317 + });
  318 + });
  319 + },
  320 + /** 删除按钮操作 */
  321 + handleDelete(row) {
  322 + const id = row.id;
  323 + this.$modal.confirm('是否确认删除限时折扣活动编号为"' + id + '"的数据项?').then(function() {
  324 + return deleteDiscountActivity(id);
  325 + }).then(() => {
  326 + this.getList();
  327 + this.$modal.msgSuccess("删除成功");
  328 + }).catch(() => {});
  329 + },
  330 + /** 关闭按钮操作 */
  331 + handleClose(row) {
  332 + const id = row.id;
  333 + this.$modal.confirm('是否确认关闭限时折扣活动编号为"' + id + '"的数据项?').then(function() {
  334 + return closeDiscountActivity(id);
  335 + }).then(() => {
  336 + this.getList();
  337 + this.$modal.msgSuccess("关闭成功");
  338 + }).catch(() => {});
  339 + },
  340 + /** 当 Form 的 SKU 发生变化时 */
  341 + changeFormSku(skuIds) {
  342 + // 处理【新增】
  343 + skuIds.forEach(skuId => {
  344 + // 获得对应的 SKU 信息
  345 + const sku = this.productSkus.find(item => item.id === skuId);
  346 + if (!sku) {
  347 + return;
  348 + }
  349 + // 判断已存在,直接跳过
  350 + const product = this.form.products.find(item => item.skuId === skuId);
  351 + if (product) {
  352 + return;
  353 + }
  354 + this.form.products.push({
  355 + skuId: sku.id,
  356 + name: sku.name,
  357 + price: sku.price,
  358 + stock: sku.stock,
  359 + spuId: sku.spuId,
  360 + spuName: sku.spuName,
  361 + discountType: PromotionDiscountTypeEnum.PRICE.type,
  362 + });
  363 + });
  364 + // 处理【移除】
  365 + this.form.products.map((product, index) => {
  366 + if (!skuIds.includes(product.skuId)) {
  367 + this.form.products.splice(index, 1);
  368 + }
  369 + });
  370 + },
  371 + /** 移除 Form 的 SKU */
  372 + removeFormSku(skuId) {
  373 + this.form.skuIds.map((id, index) => {
  374 + if (skuId === id) {
  375 + this.form.skuIds.splice(index, 1);
  376 + }
  377 + });
  378 + this.changeFormSku(this.form.skuIds);
  379 + },
  380 + }
  381 +}
  382 +</script>
yudao-ui-admin/src/views/mall/promotion/rewardActivity/index.vue 0 → 100755
  1 +<template>
  2 + <div class="app-container">
  3 +
  4 + <!-- 搜索工作栏 -->
  5 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  6 + <el-form-item label="活动名称" prop="name">
  7 + <el-input v-model="queryParams.name" placeholder="请输入活动名称" clearable @keyup.enter.native="handleQuery"/>
  8 + </el-form-item>
  9 + <el-form-item label="活动状态" prop="status">
  10 + <el-select v-model="queryParams.status" placeholder="请选择活动状态" clearable size="small">
  11 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_ACTIVITY_STATUS)"
  12 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  13 + </el-select>
  14 + </el-form-item>
  15 + <el-form-item>
  16 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  17 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  18 + </el-form-item>
  19 + </el-form>
  20 +
  21 + <!-- 操作工具栏 -->
  22 + <el-row :gutter="10" class="mb8">
  23 + <el-col :span="1.5">
  24 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
  25 + v-hasPermi="['promotion:reward-activity:create']">新增</el-button>
  26 + </el-col>
  27 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  28 + </el-row>
  29 +
  30 + <!-- 列表 -->
  31 + <el-table v-loading="loading" :data="list">
  32 + <el-table-column label="活动名称" align="center" prop="name" />
  33 + <el-table-column label="活动时间" align="center" prop="startTime" width="240">
  34 + <template slot-scope="scope">
  35 + <div>开始:{{ parseTime(scope.row.startTime) }}</div>
  36 + <div>结束:{{ parseTime(scope.row.endTime) }}</div>
  37 + </template>
  38 + </el-table-column>
  39 + <el-table-column label="状态" align="center" prop="status">
  40 + <template slot-scope="scope">
  41 + <dict-tag :type="DICT_TYPE.PROMOTION_ACTIVITY_STATUS" :value="scope.row.status" />
  42 + </template>
  43 + </el-table-column>
  44 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  45 + <template slot-scope="scope">
  46 + <span>{{ parseTime(scope.row.createTime) }}</span>
  47 + </template>
  48 + </el-table-column>
  49 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  50 + <template slot-scope="scope">
  51 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  52 + v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type"
  53 + v-hasPermi="['promotion:reward-activity:update']">修改</el-button>
  54 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleClose(scope.row)"
  55 + v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type &&
  56 + scope.row.status !== PromotionActivityStatusEnum.END.type"
  57 + v-hasPermi="['promotion:reward-activity:close']">关闭</el-button>
  58 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  59 + v-if="scope.row.status === PromotionActivityStatusEnum.CLOSE.type"
  60 + v-hasPermi="['promotion:reward-activity:delete']">删除</el-button>
  61 + </template>
  62 + </el-table-column>
  63 + </el-table>
  64 + <!-- 分页组件 -->
  65 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  66 + @pagination="getList"/>
  67 +
  68 + <!-- 对话框(添加 / 修改) -->
  69 + <el-dialog :title="title" :visible.sync="open" width="600px" v-dialogDrag append-to-body>
  70 + <el-form ref="form" :model="form" :rules="rules" label-width="80px">
  71 + <el-form-item label="活动名称" prop="name">
  72 + <el-input v-model="form.name" placeholder="请输入活动名称" />
  73 + </el-form-item>
  74 + <el-form-item label="活动时间" prop="startAndEndTime">
  75 + <el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
  76 + value-format="timestamp" placeholder="选择开始时间" style="width: 480px" />
  77 + </el-form-item>
  78 + <el-form-item label="条件类型" prop="conditionType">
  79 + <el-radio-group v-model="form.conditionType">
  80 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_CONDITION_TYPE)"
  81 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  82 + </el-radio-group>
  83 + </el-form-item>
  84 + <el-form-item label="优惠设置" prop="conditionType">
  85 + <!-- TODO 芋艿:待实现! -->
  86 + </el-form-item>
  87 + <el-form-item label="活动商品" prop="productScope">
  88 + <el-radio-group v-model="form.productScope">
  89 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_PRODUCT_SCOPE)"
  90 + :key="dict.value" :label="parseInt(dict.value)">{{dict.label}}</el-radio>
  91 + </el-radio-group>
  92 + </el-form-item>
  93 + <el-form-item v-if="form.productScope === PromotionProductScopeEnum.SPU.scope" prop="productSpuIds">
  94 + <el-select v-model="form.productSpuIds" placeholder="请选择活动商品" clearable size="small"
  95 + multiple filterable style="width: 400px">
  96 + <el-option v-for="item in productSpus" :key="item.id" :label="item.name" :value="item.id">
  97 + <span style="float: left">{{ item.name }}</span>
  98 + <span style="float: right; color: #8492a6; font-size: 13px">¥{{ (item.minPrice / 100.0).toFixed(2) }}</span>
  99 + </el-option>
  100 + </el-select>
  101 + </el-form-item>
  102 + <el-form-item label="备注" prop="remark">
  103 + <el-input v-model="form.remark" placeholder="请输入备注" />
  104 + </el-form-item>
  105 + </el-form>
  106 + <div slot="footer" class="dialog-footer">
  107 + <el-button type="primary" @click="submitForm">确 定</el-button>
  108 + <el-button @click="cancel">取 消</el-button>
  109 + </div>
  110 + </el-dialog>
  111 + </div>
  112 +</template>
  113 +
  114 +<script>
  115 +import {
  116 + createRewardActivity,
  117 + updateRewardActivity,
  118 + deleteRewardActivity,
  119 + getRewardActivity,
  120 + getRewardActivityPage,
  121 + closeRewardActivity
  122 +} from "@/api/mall/promotion/rewardActivity";
  123 +import {
  124 + PromotionConditionTypeEnum,
  125 + PromotionProductScopeEnum,
  126 + PromotionActivityStatusEnum
  127 +} from "@/utils/constants";
  128 +import {getSpuSimpleList} from "@/api/mall/product/spu";
  129 +
  130 +export default {
  131 + name: "RewardActivity",
  132 + components: {
  133 + },
  134 + data() {
  135 + return {
  136 + // 遮罩层
  137 + loading: true,
  138 + // 导出遮罩层
  139 + exportLoading: false,
  140 + // 显示搜索条件
  141 + showSearch: true,
  142 + // 总条数
  143 + total: 0,
  144 + // 满减送活动列表
  145 + list: [],
  146 + // 弹出层标题
  147 + title: "",
  148 + // 是否显示弹出层
  149 + open: false,
  150 + // 查询参数
  151 + queryParams: {
  152 + pageNo: 1,
  153 + pageSize: 10,
  154 + name: null,
  155 + status: null,
  156 + },
  157 + // 表单参数
  158 + form: {},
  159 + // 表单校验
  160 + rules: {
  161 + name: [{ required: true, message: "活动名称不能为空", trigger: "blur" }],
  162 + startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }],
  163 + conditionType: [{ required: true, message: "条件类型不能为空", trigger: "change" }],
  164 + productScope: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
  165 + productSpuIds: [{ required: true, message: "商品范围不能为空", trigger: "blur" }],
  166 + },
  167 + // 商品列表
  168 + productSpus: [],
  169 + // 如下的变量,主要为了 v-if 判断可以使用到
  170 + PromotionProductScopeEnum: PromotionProductScopeEnum,
  171 + PromotionActivityStatusEnum: PromotionActivityStatusEnum,
  172 + };
  173 + },
  174 + created() {
  175 + this.getList();
  176 + // 查询商品列表
  177 + getSpuSimpleList().then(response => {
  178 + this.productSpus = response.data
  179 + })
  180 + },
  181 + methods: {
  182 + /** 查询列表 */
  183 + getList() {
  184 + this.loading = true;
  185 + // 执行查询
  186 + getRewardActivityPage(this.queryParams).then(response => {
  187 + this.list = response.data.list;
  188 + this.total = response.data.total;
  189 + this.loading = false;
  190 + });
  191 + },
  192 + /** 取消按钮 */
  193 + cancel() {
  194 + this.open = false;
  195 + this.reset();
  196 + },
  197 + /** 表单重置 */
  198 + reset() {
  199 + this.form = {
  200 + id: undefined,
  201 + name: undefined,
  202 + startAndEndTime: undefined,
  203 + startTime: undefined,
  204 + endTime: undefined,
  205 + conditionType: PromotionConditionTypeEnum.PRICE.type,
  206 + remark: undefined,
  207 + productScope: PromotionProductScopeEnum.ALL.scope,
  208 + productSpuIds: undefined,
  209 + rules: undefined,
  210 + };
  211 + this.resetForm("form");
  212 + },
  213 + /** 搜索按钮操作 */
  214 + handleQuery() {
  215 + this.queryParams.pageNo = 1;
  216 + this.getList();
  217 + },
  218 + /** 重置按钮操作 */
  219 + resetQuery() {
  220 + this.resetForm("queryForm");
  221 + this.handleQuery();
  222 + },
  223 + /** 新增按钮操作 */
  224 + handleAdd() {
  225 + this.reset();
  226 + this.open = true;
  227 + this.title = "添加满减送活动";
  228 + },
  229 + /** 修改按钮操作 */
  230 + handleUpdate(row) {
  231 + this.reset();
  232 + const id = row.id;
  233 + getRewardActivity(id).then(response => {
  234 + this.form = response.data;
  235 + this.form.startAndEndTime = [response.data.startTime, response.data.endTime];
  236 + this.open = true;
  237 + this.title = "修改满减送活动";
  238 + });
  239 + },
  240 + /** 提交按钮 */
  241 + submitForm() {
  242 + this.$refs["form"].validate(valid => {
  243 + if (!valid) {
  244 + return;
  245 + }
  246 + this.form.startTime = this.form.startAndEndTime[0];
  247 + this.form.endTime = this.form.startAndEndTime[1];
  248 + // TODO 芋艿:临时实现
  249 + this.form.rules = [
  250 + {
  251 + limit: 1,
  252 + discountPrice: 10,
  253 + freeDelivery: true,
  254 + point: 10,
  255 + couponIds: [10, 20],
  256 + couponCounts: [1, 2]
  257 + }, {
  258 + limit: 2,
  259 + discountPrice: 20,
  260 + freeDelivery: false,
  261 + point: 20,
  262 + couponIds: [30, 40],
  263 + couponCounts: [3, 4]
  264 + }
  265 + ];
  266 + // 修改的提交
  267 + if (this.form.id != null) {
  268 + updateRewardActivity(this.form).then(response => {
  269 + this.$modal.msgSuccess("修改成功");
  270 + this.open = false;
  271 + this.getList();
  272 + });
  273 + return;
  274 + }
  275 + // 添加的提交
  276 + createRewardActivity(this.form).then(response => {
  277 + this.$modal.msgSuccess("新增成功");
  278 + this.open = false;
  279 + this.getList();
  280 + });
  281 + });
  282 + },
  283 + /** 删除按钮操作 */
  284 + handleDelete(row) {
  285 + const id = row.id;
  286 + this.$modal.confirm('是否确认删除满减送活动编号为"' + id + '"的数据项?').then(function() {
  287 + return deleteRewardActivity(id);
  288 + }).then(() => {
  289 + this.getList();
  290 + this.$modal.msgSuccess("删除成功");
  291 + }).catch(() => {});
  292 + },
  293 + /** 关闭按钮操作 */
  294 + handleClose(row) {
  295 + const id = row.id;
  296 + this.$modal.confirm('是否确认关闭满减送活动编号为"' + id + '"的数据项?').then(function() {
  297 + return closeRewardActivity(id);
  298 + }).then(() => {
  299 + this.getList();
  300 + this.$modal.msgSuccess("关闭成功");
  301 + }).catch(() => {});
  302 + }
  303 + }
  304 +};
  305 +</script>
yudao-ui-admin/src/views/system/role/index.vue
@@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
50 <el-table-column label="显示顺序" prop="sort" width="100" /> 50 <el-table-column label="显示顺序" prop="sort" width="100" />
51 <el-table-column label="状态" align="center" width="100"> 51 <el-table-column label="状态" align="center" width="100">
52 <template slot-scope="scope"> 52 <template slot-scope="scope">
53 - <el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch> 53 + <el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)"/>
54 </template> 54 </template>
55 </el-table-column> 55 </el-table-column>
56 <el-table-column label="创建时间" align="center" prop="createTime" width="180"> 56 <el-table-column label="创建时间" align="center" prop="createTime" width="180">
@@ -167,7 +167,6 @@ @@ -167,7 +167,6 @@
167 import { 167 import {
168 addRole, 168 addRole,
169 changeRoleStatus, 169 changeRoleStatus,
170 - dataScope,  
171 delRole, 170 delRole,
172 exportRole, 171 exportRole,
173 getRole, 172 getRole,