diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java index 2081e7da8..ac9713423 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/ProductSkuController.java @@ -1,14 +1,57 @@ package cn.iocoder.yudao.module.product.controller.admin.sku; +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO; +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; +import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + @Api(tags = "管理后台 - 商品 sku") @RestController @RequestMapping("/product/sku") @Validated public class ProductSkuController { + @Resource + private ProductSkuService productSkuService; + @Resource + private ProductSpuService productSpuService; + + @GetMapping("/get-option-list") + @ApiOperation("获得商品 SKU 选项的列表") +// @PreAuthorize("@ss.hasPermission('product:sku:query')") + public CommonResult> getSkuOptionList() { + // 获得 SKU 列表 + List skus = productSkuService.getSkuList(); + if (CollUtil.isEmpty(skus)) { + return success(Collections.emptyList()); + } + + // 获得对应的 SPU 映射 + Map spuMap = productSpuService.getSpuMap(convertSet(skus, ProductSkuDO::getSpuId)); + // 转换为返回结果 + List skuVOs = ProductSkuConvert.INSTANCE.convertList05(skus); + skuVOs.forEach(sku -> MapUtils.findAndThen(spuMap, sku.getSpuId(), + spu -> sku.setSpuId(spu.getId()).setSpuName(spu.getName()))); + return success(skuVOs); + } + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java new file mode 100644 index 000000000..0324bdc8d --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuOptionRespVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.product.controller.admin.sku.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@ApiModel(value = "管理后台 - 商品 SKU 选项 Response VO", description = "用于前端 SELECT 选项") +@Data +public class ProductSkuOptionRespVO { + + @ApiModelProperty(value = "主键", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "商品 SKU 名字", example = "红色") + private String name; + + @ApiModelProperty(value = "销售价格", required = true, example = "100", notes = "单位:分") + private String price; + + @ApiModelProperty(value = "库存", required = true, example = "100") + private Integer stock; + + // ========== 商品 SPU 信息 ========== + + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1") + private Long spuId; + + @ApiModelProperty(value = "商品 SPU 名字", required = true, example = "iPhone 11") + private String spuName; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java index 46e76cc63..f46c3d3bc 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuRespVO.java +++ b/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; import java.util.Date; import java.util.List; -@ApiModel("管理后台 - 商品sku Response VO") +@ApiModel("管理后台 - 商品 SKU Response VO") @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java index 0e5f57ec6..155fd0265 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/ProductSpuController.java +++ b/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 { return success(true); } + // TODO 芋艿:修改接口 @GetMapping("/get/detail") @ApiOperation("获得商品 SPU") @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) @@ -79,6 +80,14 @@ public class ProductSpuController { return success(ProductSpuConvert.INSTANCE.convertList(list)); } + @GetMapping("/get-simple-list") + @ApiOperation("获得商品 SPU 精简列表") + @PreAuthorize("@ss.hasPermission('product:spu:query')") + public CommonResult> getSpuSimpleList() { + List list = spuService.getSpuList(); + return success(ProductSpuConvert.INSTANCE.convertList02(list)); + } + @GetMapping("/page") @ApiOperation("获得商品 SPU 分页") @PreAuthorize("@ss.hasPermission('product:spu:query')") diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java new file mode 100755 index 000000000..ea2811f8b --- /dev/null +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuSimpleRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.product.controller.admin.spu.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("管理后台 - 商品 SPU 精简 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProductSpuSimpleRespVO extends ProductSpuBaseVO { + + @ApiModelProperty(value = "主键", required = true, example = "1") + private Long id; + + @ApiModelProperty(value = "商品名称", required = true, example = "芋道") + private String name; + + @ApiModelProperty(value = " 最小价格,单位使用:分", required = true, example = "1024") + private Integer minPrice; + + @ApiModelProperty(value = "最大价格,单位使用:分", required = true, example = "1024") + private Integer maxPrice; + +} diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java index 4b8bb45f0..c96cd41db 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java +++ b/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; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuOptionRespVO; import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; @@ -11,7 +12,7 @@ import org.mapstruct.factory.Mappers; import java.util.List; /** - * 商品sku Convert + * 商品 SKU Convert * * @author 芋道源码 */ @@ -36,4 +37,6 @@ public interface ProductSkuConvert { List convertList04(List list); + List convertList05(List skus); + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java index 26fe6a028..de7adde73 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java +++ b/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 { AppSpuPageRespVO convertAppResp(ProductSpuDO list); List convertList2(List list); - + + List convertList02(List list); + } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java index 25b91525c..f953534ed 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java +++ b/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 { * 商品属性 */ @Data + @NoArgsConstructor @AllArgsConstructor public static class Property { @@ -130,19 +131,5 @@ public class ProductSkuDO extends BaseDO { } - // TODO ========== 待定字段:yv ========= - // TODO brokerage:一级返佣 - // TODO brokerage_two:二级返佣 - // TODO pink_price:拼团价 - // TODO pink_stock:拼团库存 - // TODO seckill_price:秒杀价 - // TODO seckill_stock:秒杀库存 - // TODO integral:需要积分 - - // TODO ========== 待定字段:cf ========= - // TODO type 活动显示排序 0=默认 1=秒 2=砍价 3=拼团 - // TODO quota 活动限购数量 - // TODO quota_show 活动限购数量显示 - } diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java index acde66a4a..8bdfe49d9 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java +++ b/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; public interface ProductSkuService { /** - * 删除商品sku + * 删除商品 SKU * * @param id 编号 */ void deleteSku(Long id); /** - * 获得商品sku + * 获得商品 SKU 信息 * * @param id 编号 - * @return 商品sku + * @return 商品 SKU 信息 */ ProductSkuDO getSku(Long id); /** - * 获得商品sku列表 + * 获得商品 SKU 列表 + * + * @return 商品sku列表 + */ + List getSkuList(); + + /** + * 获得商品 SKU 列表 * * @param ids 编号 * @return 商品sku列表 diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java index 952fbeb74..d9b90b0f3 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java @@ -61,6 +61,11 @@ public class ProductSkuServiceImpl implements ProductSkuService { return productSkuMapper.selectById(id); } + @Override + public List getSkuList() { + return productSkuMapper.selectList(); + } + @Override public List getSkuList(Collection ids) { return productSkuMapper.selectBatchIds(ids); diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java index 2c5a9af91..6ae7e8996 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuService.java +++ b/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; import javax.validation.Valid; import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * 商品 SPU Service 接口 @@ -63,6 +66,23 @@ public interface ProductSpuService { */ List getSpuList(Collection ids); + /** + * 获得商品 SPU 映射 + * + * @param ids 编号数组 + * @return 商品 SPU 映射 + */ + default Map getSpuMap(Collection ids) { + return convertMap(getSpuList(ids), ProductSpuDO::getId); + } + + /** + * 获得所有商品 SPU 列表 + * + * @return 商品 SPU 列表 + */ + List getSpuList(); + /** * 获得商品 SPU 分页 * diff --git a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java index 2e6e4b174..b332af306 100755 --- a/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java +++ b/yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java @@ -176,6 +176,11 @@ public class ProductSpuServiceImpl implements ProductSpuService { return productSpuMapper.selectBatchIds(ids); } + @Override + public List getSpuList() { + return productSpuMapper.selectList(); + } + @Override public PageResult getSpuPage(ProductSpuPageReqVO pageReqVO) { // 库存告警的 SPU 编号的集合 diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java index 99cb36ae6..cda6d99d6 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateRespDTO.java @@ -48,9 +48,17 @@ public class PriceCalculateRespDTO { * 商品原价(总),单位:分 * * 基于 {@link OrderItem#getOriginalPrice()} 求和 + * * 对应 taobao 的 trade.total_fee 字段 */ private Integer originalPrice; + /** + * 订单原价(总),单位:分 + * + * 基于 {@link OrderItem#getPayPrice()} 求和 + * 和 {@link #originalPrice} 的差异:去除商品级优惠 + */ + private Integer orderPrice; /** * 订单优惠(总),单位:分 * @@ -82,6 +90,7 @@ public class PriceCalculateRespDTO { * - {@link #couponPrice} * - {@link #pointPrice} * + {@link #deliveryPrice} + * - {@link #discountPrice} */ private Integer payPrice; /** diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java index 4b6cb8ca6..e405a0c59 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java @@ -3,14 +3,19 @@ package cn.iocoder.yudao.module.promotion.enums; import cn.iocoder.yudao.framework.common.exception.ErrorCode; /** - * market 错误码枚举类 - *

+ * promotion 错误码枚举类 + * * market 系统,使用 1-003-000-000 段 */ public interface ErrorCodeConstants { - // ========== 促销活动相关 1003001000 ============ TODO 芋艿:看看是不是要删除掉 - ErrorCode ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "促销活动不存在"); + // ========== 促销活动相关 1003001000 ============ + ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "限时折扣活动不存在"); + ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003006001, "存在商品参加了其它限时折扣活动"); + ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1003006002, "限时折扣活动已关闭,不能修改"); + ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1003006003, "限时折扣活动未关闭,不能删除"); + ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1003006004, "限时折扣活动已关闭,不能重复关闭"); + ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1003006004, "限时折扣活动已结束,不能关闭"); // ========== Banner 相关 1003002000 ============ ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1003002000, "Banner 不存在"); @@ -23,4 +28,19 @@ public interface ErrorCodeConstants { ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1003004000, "优惠劵模板不存在"); ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1003004001, "发放数量不能小于已领取数量({})"); + // ========== 优惠劵模板 1003005000 ========== + ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1003005000, "优惠劵不存在"); + ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1003005001, "回收优惠劵失败,优惠劵已被使用"); + + // ========== 满减送活动 1003006000 ========== + ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1003006000, "满减送活动不存在"); + ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003006001, "存在商品参加了其它满减送活动"); + ErrorCode REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1003006002, "满减送活动已关闭,不能修改"); + ErrorCode REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1003006003, "满减送活动未关闭,不能删除"); + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1003006004, "满减送活动已关闭,不能重复关闭"); + ErrorCode REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1003006004, "满减送活动已结束,不能关闭"); + + // ========== Price 相关 1003007000 ============ + ErrorCode PRICE_CALCULATE_PAY_PRICE_ILLEGAL = new ErrorCode(1003007000, "支付价格计算异常,原因:价格小于等于 0"); + } diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java new file mode 100644 index 000000000..320345d85 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponStatusEnum.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.promotion.enums.coupon; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +/** + * 优惠劵状态枚举 + * + * @author 芋道源码 + */ +@AllArgsConstructor +@Getter +public enum CouponStatusEnum implements IntArrayValuable { + + UNUSED(1, "未使用"), + USED(2, "已使用"), + EXPIRE(3, "已过期"), + ; + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CouponStatusEnum::getStatus).toArray(); + + /** + * 值 + */ + private final Integer status; + /** + * 名字 + */ + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java index e1c13634f..ce7974142 100644 --- a/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java +++ b/yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/coupon/CouponTakeTypeEnum.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.promotion.enums.coupon; import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; import java.util.Arrays; @@ -9,6 +11,8 @@ import java.util.Arrays; * * @author 芋道源码 */ +@AllArgsConstructor +@Getter public enum CouponTakeTypeEnum implements IntArrayValuable { BY_USER(1, "直接领取"), // 用户可在首页、每日领劵直接领取 @@ -26,19 +30,6 @@ public enum CouponTakeTypeEnum implements IntArrayValuable { */ private final String name; - CouponTakeTypeEnum(Integer value, String name) { - this.value = value; - this.name = name; - } - - public Integer getValue() { - return value; - } - - public String getName() { - return name; - } - @Override public int[] array() { return ARRAYS; diff --git a/yudao-module-mall/yudao-module-promotion-biz/pom.xml b/yudao-module-mall/yudao-module-promotion-biz/pom.xml index e8b764019..266cb1511 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/pom.xml +++ b/yudao-module-mall/yudao-module-promotion-biz/pom.xml @@ -29,6 +29,11 @@ yudao-module-product-api ${revision} + + cn.iocoder.boot + yudao-module-member-api + ${revision} + diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java new file mode 100755 index 000000000..0a6facbc9 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponController.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Api(tags = "管理后台 - 优惠劵") +@RestController +@RequestMapping("/promotion/coupon") +@Validated +public class CouponController { + + @Resource + private CouponService couponService; + @Resource + private MemberUserApi memberUserApi; + +// @GetMapping("/get") +// @ApiOperation("获得优惠劵") +// @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) +// @PreAuthorize("@ss.hasPermission('promotion:coupon:query')") +// public CommonResult getCoupon(@RequestParam("id") Long id) { +// CouponDO coupon = couponService.getCoupon(id); +// return success(CouponConvert.INSTANCE.convert(coupon)); +// } + + @DeleteMapping("/delete") + @ApiOperation("回收优惠劵") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('promotion:coupon:delete')") + public CommonResult deleteCoupon(@RequestParam("id") Long id) { + couponService.deleteCoupon(id); + return success(true); + } + + @GetMapping("/page") + @ApiOperation("获得优惠劵分页") + @PreAuthorize("@ss.hasPermission('promotion:coupon:query')") + public CommonResult> getCouponPage(@Valid CouponPageReqVO pageVO) { + PageResult pageResult = couponService.getCouponPage(pageVO); + PageResult pageResulVO = CouponConvert.INSTANCE.convertPage(pageResult); + if (CollUtil.isEmpty(pageResulVO.getList())) { + return success(pageResulVO); + } + // 读取用户信息,进行拼接 + Set userIds = convertSet(pageResult.getList(), CouponDO::getUserId); + Map userMap = memberUserApi.getUserMap(userIds); + pageResulVO.getList().forEach(itemRespVO -> MapUtils.findAndThen(userMap, itemRespVO.getUserId(), + userRespDTO -> itemRespVO.setNickname(userRespDTO.getNickname()))); + return success(pageResulVO); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java index 4f1d51c61..76efd2daa 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/CouponTemplateController.java @@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.promotion.controller.admin.coupon; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateRespVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.*; import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; @@ -45,6 +42,14 @@ public class CouponTemplateController { return success(true); } + @PutMapping("/update-status") + @ApiOperation("更新优惠劵模板状态") + @PreAuthorize("@ss.hasPermission('promotion:coupon-template:update')") + public CommonResult updateCouponTemplateStatus(@Valid @RequestBody CouponTemplateUpdateStatusReqVO reqVO) { + couponTemplateService.updateCouponTemplateStatus(reqVO.getId(), reqVO.getStatus()); + return success(true); + } + @DeleteMapping("/delete") @ApiOperation("删除优惠劵模板") @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java new file mode 100755 index 000000000..1aefbe80e --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponBaseVO.java @@ -0,0 +1,103 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; + +/** +* 优惠劵 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class CouponBaseVO { + + // ========== 基本信息 BEGIN ========== + @ApiModelProperty(value = "优惠劵模板编号", required = true, example = "1024") + @NotNull(message = "优惠劵模板编号不能为空") + private Integer templateId; + + @ApiModelProperty(value = "优惠劵名", required = true, example = "春节送送送") + @NotNull(message = "优惠劵名不能为空") + private String name; + + @ApiModelProperty(value = "优惠码状态", required = true, example = "1", notes = "参见 CouponStatusEnum 枚举") + private Integer status; + + // ========== 基本信息 END ========== + + // ========== 领取情况 BEGIN ========== + @ApiModelProperty(value = "用户编号", required = true, example = "1") + @NotNull(message = "用户编号不能为空") + private Long userId; + + @ApiModelProperty(value = "领取方式", required = true, example = "1", notes = "参见 CouponTakeTypeEnum 枚举类") + @NotNull(message = "领取方式不能为空") + private Integer takeType; + // ========== 领取情况 END ========== + + // ========== 使用规则 BEGIN ========== + @ApiModelProperty(value = "是否设置满多少金额可用", required = true, example = "100", notes = "单位:分;0 - 不限制") + @NotNull(message = "是否设置满多少金额可用不能为空") + private Integer usePrice; + + @ApiModelProperty(value = "固定日期 - 生效开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date validStartTime; + + @ApiModelProperty(value = "固定日期 - 生效结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date validEndTime; + + @ApiModelProperty(value = "商品范围", required = true, example = "1", notes = "参见 PromotionProductScopeEnum 枚举类") + @NotNull(message = "商品范围不能为空") + @InEnum(PromotionProductScopeEnum.class) + private Integer productScope; + + @ApiModelProperty(value = "商品 SPU 编号的数组", example = "1,3") + private List productSpuIds; + // ========== 使用规则 END ========== + + // ========== 使用效果 BEGIN ========== + @ApiModelProperty(value = "优惠类型", required = true, example = "1", notes = "参见 PromotionDiscountTypeEnum 枚举") + @NotNull(message = "优惠类型不能为空") + @InEnum(PromotionDiscountTypeEnum.class) + private Integer discountType; + + @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80") + private Integer discountPercent; + + @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分") + @Min(value = 0, message = "优惠金额需要大于等于 0") + private Integer discountPrice; + + @ApiModelProperty(value = "折扣上限", example = "100", notes = "单位:分,仅在 discountType 为 PERCENT 使用") + private Integer discountLimitPrice; + // ========== 使用效果 END ========== + + // ========== 使用情况 BEGIN ========== + + @ApiModelProperty(value = "使用订单号", example = "4096") + private Long useOrderId; + + @ApiModelProperty(value = "使用时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) + private Date useTime; + + // ========== 使用情况 END ========== + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageItemRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageItemRespVO.java new file mode 100755 index 000000000..88bc364bd --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageItemRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ApiModel("管理后台 - 优惠劵分页的每一项 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponPageItemRespVO extends CouponRespVO { + + @ApiModelProperty(value = "用户昵称", example = "老芋艿") + private String nickname; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java new file mode 100755 index 000000000..0f9fbb40e --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponPageReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 优惠劵分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponPageReqVO extends PageParam { + + @ApiModelProperty(value = "优惠劵模板编号", example = "2048") + private Long templateId; + + @ApiModelProperty(value = "优惠码状态", example = "1", notes = "参见 CouponStatusEnum 枚举") + private Integer status; + + @ApiModelProperty(value = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date[] createTime; + + @ApiModelProperty(value = "用户昵称", example = "芋艿", notes = "模糊匹配") + private String nickname; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponRespVO.java new file mode 100755 index 000000000..32f19c5b9 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/coupon/CouponRespVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.Date; + +@ApiModel("管理后台 - 优惠劵 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CouponRespVO extends CouponBaseVO { + + @ApiModelProperty(value = "优惠劵编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java similarity index 89% rename from yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateBaseVO.java rename to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java index f41b8181b..0c50db779 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateBaseVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateBaseVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -19,6 +20,7 @@ import java.util.List; import java.util.Objects; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT; /** * 优惠劵模板 Base VO,提供给添加、修改、详细的子 VO 使用 @@ -62,10 +64,12 @@ public class CouponTemplateBaseVO { @ApiModelProperty(value = "固定日期 - 生效开始时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) private Date validStartTime; @ApiModelProperty(value = "固定日期 - 生效结束时间") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @JsonFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND, timezone = TIME_ZONE_DEFAULT) private Date validEndTime; @ApiModelProperty(value = "领取日期 - 开始天数") @@ -82,15 +86,14 @@ public class CouponTemplateBaseVO { private Integer discountType; @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80") - @Min(value = 1) private Integer discountPercent; @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分") - @Min(value = 1) + @Min(value = 0, message = "优惠金额需要大于等于 0") private Integer discountPrice; @ApiModelProperty(value = "折扣上限", example = "100", notes = "单位:分,仅在 discountType 为 PERCENT 使用") - private Integer discountPriceLimit; + private Integer discountLimitPrice; @AssertTrue(message = "商品 SPU 编号的数组不能为空") @JsonIgnore @@ -127,11 +130,11 @@ public class CouponTemplateBaseVO { || fixedEndTerm != null; } - @AssertTrue(message = "折扣百分比不能为空") + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99") @JsonIgnore public boolean isDiscountPercentValid() { return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) - || discountPercent != null; + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99); } @AssertTrue(message = "优惠金额不能为空") @@ -143,9 +146,9 @@ public class CouponTemplateBaseVO { @AssertTrue(message = "折扣上限不能为空") @JsonIgnore - public boolean isDiscountPriceLimit() { + public boolean isDiscountLimitPriceValid() { return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) - || discountPriceLimit != null; + || discountLimitPrice != null; } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateCreateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateCreateReqVO.java similarity index 96% rename from yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateCreateReqVO.java rename to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateCreateReqVO.java index 60f658b90..91bfb0a5f 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateCreateReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateCreateReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; import io.swagger.annotations.ApiModel; import lombok.Data; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplatePageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java similarity index 98% rename from yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplatePageReqVO.java rename to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java index 2092112c3..a6c3ec6ae 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplatePageReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplatePageReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateRespVO.java similarity index 98% rename from yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateRespVO.java rename to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateRespVO.java index 835149027..8f8abd9c2 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateRespVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateRespVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateUpdateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateReqVO.java similarity index 97% rename from yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateUpdateReqVO.java rename to yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateReqVO.java index afa62ce6c..8e5e8723a 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/CouponTemplateUpdateReqVO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateReqVO.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo; +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateStatusReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateStatusReqVO.java new file mode 100644 index 000000000..32e020637 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/coupon/vo/template/CouponTemplateUpdateStatusReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@ApiModel("管理后台 - 优惠劵模板更新状态 Request VO") +@Data +public class CouponTemplateUpdateStatusReqVO { + + @ApiModelProperty(value = "优惠劵模板编号", required = true, example = "1024") + @NotNull(message = "优惠劵模板编号不能为空") + private Long id; + + @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java new file mode 100755 index 000000000..332a1b822 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/DiscountActivityController.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 限时折扣活动") +@RestController +@RequestMapping("/promotion/discount-activity") +@Validated +public class DiscountActivityController { + + @Resource + private DiscountActivityService discountActivityService; + + @PostMapping("/create") + @ApiOperation("创建限时折扣活动") + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:create')") + public CommonResult createDiscountActivity(@Valid @RequestBody DiscountActivityCreateReqVO createReqVO) { + return success(discountActivityService.createDiscountActivity(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新限时折扣活动") + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:update')") + public CommonResult updateDiscountActivity(@Valid @RequestBody DiscountActivityUpdateReqVO updateReqVO) { + discountActivityService.updateDiscountActivity(updateReqVO); + return success(true); + } + + @PutMapping("/close") + @ApiOperation("关闭限时折扣活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:close')") + public CommonResult closeRewardActivity(@RequestParam("id") Long id) { + discountActivityService.closeRewardActivity(id); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除限时折扣活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:delete')") + public CommonResult deleteDiscountActivity(@RequestParam("id") Long id) { + discountActivityService.deleteDiscountActivity(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得限时折扣活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')") + public CommonResult getDiscountActivity(@RequestParam("id") Long id) { + DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id); + if (discountActivity == null) { + return success(null); + } + // 拼接结果 + List discountProducts = discountActivityService.getDiscountProductsByActivityId(id); + return success(DiscountActivityConvert.INSTANCE.convert(discountActivity, discountProducts)); + } + + @GetMapping("/page") + @ApiOperation("获得限时折扣活动分页") + @PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')") + public CommonResult> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) { + PageResult pageResult = discountActivityService.getDiscountActivityPage(pageVO); + return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/package-info.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/package-info.java deleted file mode 100644 index 06f40bb4f..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * TODO 占位 - */ -package cn.iocoder.yudao.module.promotion.controller.admin.discount; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java new file mode 100755 index 000000000..e1eafcca9 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityBaseVO.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.Date; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 限时折扣活动 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class DiscountActivityBaseVO { + + @ApiModelProperty(value = "活动标题", required = true, example = "一个标题") + @NotNull(message = "活动标题不能为空") + private String name; + + @ApiModelProperty(value = "开始时间", required = true) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date startTime; + + @ApiModelProperty(value = "结束时间", required = true) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date endTime; + + @ApiModelProperty(value = "备注", example = "我是备注") + private String remark; + + @ApiModel("商品") + @Data + public static class Product { + + @ApiModelProperty(value = "商品 SPU 编号", required = true, example = "1") + @NotNull(message = "商品 SPU 编号不能为空") + private Long spuId; + + @ApiModelProperty(value = "商品 SKU 编号", required = true, example = "1") + @NotNull(message = "商品 SKU 编号不能为空") + private Long skuId; + + @ApiModelProperty(value = "优惠类型", required = true, example = "1", notes = "参见 PromotionDiscountTypeEnum 枚举") + @NotNull(message = "优惠类型不能为空") + @InEnum(PromotionDiscountTypeEnum.class) + private Integer discountType; + + @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说,80% 为 80") + private Integer discountPercent; + + @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分") + @Min(value = 0, message = "优惠金额需要大于等于 0") + private Integer discountPrice; + + @AssertTrue(message = "折扣百分比需要大于等于 1,小于等于 99") + @JsonIgnore + public boolean isDiscountPercentValid() { + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) + || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99); + } + + @AssertTrue(message = "优惠金额不能为空") + @JsonIgnore + public boolean isDiscountPriceValid() { + return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PRICE.getType()) + || discountPrice != null; + } + + } +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java new file mode 100755 index 000000000..35de6faf2 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityCreateReqVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +@ApiModel("管理后台 - 限时折扣活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityCreateReqVO extends DiscountActivityBaseVO { + + /** + * 商品列表 + */ + @NotEmpty(message = "商品列表不能为空") + @Valid + private List products; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityDetailRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityDetailRespVO.java new file mode 100755 index 000000000..1dfdeec18 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityDetailRespVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.List; + +@ApiModel("管理后台 - 限时折扣活动的详细 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityDetailRespVO extends DiscountActivityRespVO { + + /** + * 商品列表 + */ + private List products; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityPageReqVO.java new file mode 100755 index 000000000..84f068df4 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityPageReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@ApiModel("管理后台 - 限时折扣活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityPageReqVO extends PageParam { + + @ApiModelProperty(value = "活动标题", example = "一个标题") + private String name; + + @ApiModelProperty(value = "活动状态", example = "1") + private Integer status; + + @ApiModelProperty(value = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date[] createTime; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java new file mode 100755 index 000000000..fda1b23fc --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityRespVO.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +@ApiModel("管理后台 - 限时折扣活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityRespVO extends DiscountActivityBaseVO { + + @ApiModelProperty(value = "活动编号", required = true, example = "1024") + private Long id; + + @ApiModelProperty(value = "活动状态", required = true, example = "1") + @NotNull(message = "活动状态不能为空") + private Integer status; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java new file mode 100755 index 000000000..0f3b6e435 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/discount/vo/DiscountActivityUpdateReqVO.java @@ -0,0 +1,31 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@ApiModel("管理后台 - 限时折扣活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class DiscountActivityUpdateReqVO extends DiscountActivityBaseVO { + + @ApiModelProperty(value = "活动编号", required = true, example = "1024") + @NotNull(message = "活动编号不能为空") + private Long id; + + /** + * 商品列表 + */ + @NotEmpty(message = "商品列表不能为空") + @Valid + private List products; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java new file mode 100755 index 000000000..043571e5e --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/RewardActivityController.java @@ -0,0 +1,83 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Api(tags = "管理后台 - 满减送活动") +@RestController +@RequestMapping("/promotion/reward-activity") +@Validated +public class RewardActivityController { + + @Resource + private RewardActivityService rewardActivityService; + + @PostMapping("/create") + @ApiOperation("创建满减送活动") + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:create')") + public CommonResult createRewardActivity(@Valid @RequestBody RewardActivityCreateReqVO createReqVO) { + return success(rewardActivityService.createRewardActivity(createReqVO)); + } + + @PutMapping("/update") + @ApiOperation("更新满减送活动") + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:update')") + public CommonResult updateRewardActivity(@Valid @RequestBody RewardActivityUpdateReqVO updateReqVO) { + rewardActivityService.updateRewardActivity(updateReqVO); + return success(true); + } + + @PutMapping("/close") + @ApiOperation("关闭满减送活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:close')") + public CommonResult closeRewardActivity(@RequestParam("id") Long id) { + rewardActivityService.closeRewardActivity(id); + return success(true); + } + + @DeleteMapping("/delete") + @ApiOperation("删除满减送活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:delete')") + public CommonResult deleteRewardActivity(@RequestParam("id") Long id) { + rewardActivityService.deleteRewardActivity(id); + return success(true); + } + + @GetMapping("/get") + @ApiOperation("获得满减送活动") + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')") + public CommonResult getRewardActivity(@RequestParam("id") Long id) { + RewardActivityDO rewardActivity = rewardActivityService.getRewardActivity(id); + return success(RewardActivityConvert.INSTANCE.convert(rewardActivity)); + } + + @GetMapping("/page") + @ApiOperation("获得满减送活动分页") + @PreAuthorize("@ss.hasPermission('promotion:reward-activity:query')") + public CommonResult> getRewardActivityPage(@Valid RewardActivityPageReqVO pageVO) { + PageResult pageResult = rewardActivityService.getRewardActivityPage(pageVO); + return success(RewardActivityConvert.INSTANCE.convertPage(pageResult)); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java new file mode 100755 index 000000000..d201058fa --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityBaseVO.java @@ -0,0 +1,99 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.Valid; +import javax.validation.constraints.AssertTrue; +import javax.validation.constraints.Future; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** +* 满减送活动 Base VO,提供给添加、修改、详细的子 VO 使用 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 +*/ +@Data +public class RewardActivityBaseVO { + + @ApiModelProperty(value = "活动标题", required = true, example = "满啦满啦") + @NotNull(message = "活动标题不能为空") + private String name; + + @ApiModelProperty(value = "开始时间", required = true) + @NotNull(message = "开始时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private Date startTime; + + @ApiModelProperty(value = "结束时间", required = true) + @NotNull(message = "结束时间不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + @Future(message = "结束时间必须大于当前时间") + private Date endTime; + + @ApiModelProperty(value = "备注", example = "biubiubiu") + private String remark; + + @ApiModelProperty(value = "条件类型", required = true, example = "1") + @NotNull(message = "条件类型不能为空") + @InEnum(value = PromotionConditionTypeEnum.class, message = "条件类型必须是 {value}") + private Integer conditionType; + + @ApiModelProperty(value = "商品范围", required = true, example = "1") + @NotNull(message = "商品范围不能为空") + @InEnum(value = PromotionConditionTypeEnum.class, message = "商品范围必须是 {value}") + private Integer productScope; + + @ApiModelProperty(value = "商品 SPU 编号的数组", example = "1,2,3") + private List productSpuIds; + + /** + * 优惠规则的数组 + */ + @Valid // 校验下子对象 + private List rules; + + @ApiModel("优惠规则") + @Data + public static class Rule { + + @ApiModelProperty(value = "优惠门槛", required = true, example = "100", notes = "1. 满 N 元,单位:分; 2. 满 N 件") + @Min(value = 1L, message = "优惠门槛必须大于等于 1") + private Integer limit; + + @ApiModelProperty(value = "优惠价格", required = true, example = "100", notes = "单位:分") + @Min(value = 1L, message = "优惠价格必须大于等于 1") + private Integer discountPrice; + + @ApiModelProperty(value = "是否包邮", required = true, example = "true") + private Boolean freeDelivery; + + @ApiModelProperty(value = "赠送的积分", required = true, example = "100") + @Min(value = 1L, message = "赠送的积分必须大于等于 1") + private Integer point; + + @ApiModelProperty(value = "赠送的优惠劵编号的数组", example = "1,2,3") + private List couponIds; + + @ApiModelProperty(value = "赠送的优惠卷数量的数组", example = "1,2,3") + private List couponCounts; + + @AssertTrue(message = "优惠劵和数量必须一一对应") + @JsonIgnore + public boolean isCouponCountsValid() { + return CollUtil.size(couponCounts) == CollUtil.size(couponCounts); + } + + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityCreateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityCreateReqVO.java new file mode 100755 index 000000000..6a7251021 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityCreateReqVO.java @@ -0,0 +1,12 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import lombok.*; +import io.swagger.annotations.*; + +@ApiModel("管理后台 - 满减送活动创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityCreateReqVO extends RewardActivityBaseVO { + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityPageReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityPageReqVO.java new file mode 100755 index 000000000..5a8d2ba6d --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityPageReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import lombok.*; +import io.swagger.annotations.*; +import cn.iocoder.yudao.framework.common.pojo.PageParam; + +@ApiModel("管理后台 - 满减送活动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityPageReqVO extends PageParam { + + @ApiModelProperty(value = "活动标题", example = "满啦满啦") + private String name; + + @ApiModelProperty(value = "活动状态", example = "1") + private Integer status; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityRespVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityRespVO.java new file mode 100755 index 000000000..94ccccd0d --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityRespVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import lombok.*; +import java.util.*; +import io.swagger.annotations.*; + +@ApiModel("管理后台 - 满减送活动 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityRespVO extends RewardActivityBaseVO { + + @ApiModelProperty(value = "活动编号", required = true, example = "1024") + private Integer id; + + @ApiModelProperty(value = "活动状态", required = true, example = "1") + private Integer status; + + @ApiModelProperty(value = "创建时间", required = true) + private Date createTime; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java new file mode 100755 index 000000000..659deee3d --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/reward/vo/RewardActivityUpdateReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.promotion.controller.admin.reward.vo; + +import lombok.*; +import io.swagger.annotations.*; +import javax.validation.constraints.*; + +@ApiModel("管理后台 - 满减送活动更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RewardActivityUpdateReqVO extends RewardActivityBaseVO { + + @ApiModelProperty(value = "活动编号", required = true, example = "1024") + @NotNull(message = "活动编号不能为空") + private Long id; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java new file mode 100755 index 000000000..281318f7d --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.promotion.convert.coupon; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageItemRespVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 优惠劵 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface CouponConvert { + + CouponConvert INSTANCE = Mappers.getMapper(CouponConvert.class); + + PageResult convertPage(PageResult page); + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java index 5fedd9678..22d78f46f 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponTemplateConvert.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.promotion.convert.coupon; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateRespVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java new file mode 100755 index 000000000..07d2e03ab --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/DiscountActivityConvert.java @@ -0,0 +1,102 @@ +package cn.iocoder.yudao.module.promotion.convert.discount; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.*; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; +import java.util.Map; + +/** + * 限时折扣活动 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface DiscountActivityConvert { + + DiscountActivityConvert INSTANCE = Mappers.getMapper(DiscountActivityConvert.class); + + DiscountActivityDO convert(DiscountActivityCreateReqVO bean); + + DiscountActivityDO convert(DiscountActivityUpdateReqVO bean); + + DiscountActivityRespVO convert(DiscountActivityDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + DiscountProductDetailBO convert(DiscountProductDO product); + + default List convertList(List products, Map activityMap) { + return CollectionUtils.convertList(products, product -> { + DiscountProductDetailBO detail = convert(product); + MapUtils.findAndThen(activityMap, product.getActivityId(), activity -> { + detail.setActivityName(activity.getName()); + }); + return detail; + }); + } + + DiscountProductDO convert(DiscountActivityBaseVO.Product bean); + + DiscountActivityDetailRespVO convert(DiscountActivityDO activity, List products); + + // =========== 比较是否相等 ========== + /** + * 比较两个限时折扣商品是否相等 + * + * @param productDO 数据库中的商品 + * @param productVO 前端传入的商品 + * @return 是否匹配 + */ + @SuppressWarnings("DuplicatedCode") + default boolean isEquals(DiscountProductDO productDO, DiscountActivityBaseVO.Product productVO) { + if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) + || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) + || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) { + return false; + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { + return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice()); + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) { + return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent()); + } + return true; + } + + /** + * 比较两个限时折扣商品是否相等 + * 注意,比较时忽略 id 编号 + * + * @param productDO 商品 1 + * @param productVO 商品 2 + * @return 是否匹配 + */ + @SuppressWarnings("DuplicatedCode") + default boolean isEquals(DiscountProductDO productDO, DiscountProductDO productVO) { + if (ObjectUtil.notEqual(productDO.getSpuId(), productVO.getSpuId()) + || ObjectUtil.notEqual(productDO.getSkuId(), productVO.getSkuId()) + || ObjectUtil.notEqual(productDO.getDiscountType(), productVO.getDiscountType())) { + return false; + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PRICE.getType())) { + return ObjectUtil.equal(productDO.getDiscountPrice(), productVO.getDiscountPrice()); + } + if (productDO.getDiscountType().equals(PromotionDiscountTypeEnum.PERCENT.getType())) { + return ObjectUtil.equal(productDO.getDiscountPercent(), productVO.getDiscountPercent()); + } + return true; + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/package-info.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/package-info.java deleted file mode 100644 index ce5ff843e..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/discount/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * TODO 占位 - */ -package cn.iocoder.yudao.module.promotion.convert.discount; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/price/PriceConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/price/PriceConvert.java index bca6bb95c..cafe81526 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/price/PriceConvert.java +++ b/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 { orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice()); priceCalculate.getOrder().getItems().add(orderItem); // 补充价格信息到 Order 中 - order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice()).setPayPrice(order.getOriginalPrice()); + order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice()) + .setOrderPrice(order.getOriginalPrice()).setPayPrice(order.getOriginalPrice()); }); return priceCalculate; } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java new file mode 100755 index 000000000..5343656ed --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/reward/RewardActivityConvert.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.promotion.convert.reward; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityRespVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 满减送活动 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface RewardActivityConvert { + + RewardActivityConvert INSTANCE = Mappers.getMapper(RewardActivityConvert.class); + + RewardActivityDO convert(RewardActivityCreateReqVO bean); + + RewardActivityDO convert(RewardActivityUpdateReqVO bean); + + RewardActivityRespVO convert(RewardActivityDO bean); + + PageResult convertPage(PageResult page); + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java index 9bf41f317..89f7cbfb9 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponDO.java @@ -1,11 +1,14 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTakeTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; @@ -14,9 +17,11 @@ import java.util.List; /** * 优惠劵 DO + * + * @author 芋道源码 */ @TableName(value = "promotion_coupon", autoResultMap = true) -@KeySequence("promotion_coupo_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@KeySequence("promotion_coupon_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) public class CouponDO extends BaseDO { @@ -35,21 +40,13 @@ public class CouponDO extends BaseDO { /** * 优惠劵名 * - * 冗余自 {@link CouponTemplateDO} 的 title - * - * TODO 芋艿,暂时不考虑冗余的更新 + * 冗余 {@link CouponTemplateDO#getName()} */ - private String title; -// /** -// * 核销码 -// */ -// private String verifyCode; + private String name; /** * 优惠码状态 * - * 1-未使用 - * 2-已使用 - * 3-已失效 + * 枚举 {@link CouponStatusEnum} */ private Integer status; @@ -58,13 +55,14 @@ public class CouponDO extends BaseDO { // ========== 领取情况 BEGIN ========== /** * 用户编号 + * + * 关联 MemberUserDO 的 id 字段 */ - private Integer userId; + private Long userId; /** * 领取类型 * - * 1 - 用户主动领取 - * 2 - 后台自动发放 + * 枚举 {@link CouponTakeTypeEnum} */ private Integer takeType; // ========== 领取情况 END ========== @@ -72,8 +70,10 @@ public class CouponDO extends BaseDO { // ========== 使用规则 BEGIN ========== /** * 是否设置满多少金额可用,单位:分 + * + * 冗余 {@link CouponTemplateDO#getUsePrice()} */ - private Integer priceAvailable; + private Integer usePrice; /** * 生效开始时间 */ @@ -90,50 +90,49 @@ public class CouponDO extends BaseDO { private Integer productScope; /** * 商品 SPU 编号的数组 + * + * 冗余 {@link CouponTemplateDO#getProductSpuIds()} */ - @TableField(typeHandler = JacksonTypeHandler.class) - private List spuIds; + @TableField(typeHandler = LongListTypeHandler.class) + private List productSpuIds; // ========== 使用规则 END ========== // ========== 使用效果 BEGIN ========== /** - * 优惠类型 + * 折扣类型 * - * 1-代金卷 - * 2-折扣卷 + * 冗余 {@link CouponTemplateDO#getDiscountType()} */ - private Integer preferentialType; + private Integer discountType; /** - * 折扣 - */ - private Integer percentOff; - /** - * 优惠金额,单位:分。 - */ - private Integer priceOff; - /** - * 折扣上限,仅在 {@link #preferentialType} 等于 2 时生效。 + * 折扣百分比 * - * 例如,折扣上限为 20 元,当使用 8 折优惠券,订单金额为 1000 元时,最高只可折扣 20 元,而非 80 元。 + * 冗余 {@link CouponTemplateDO#getDiscountPercent()} */ - private Integer discountPriceLimit; + private Integer discountPercent; + /** + * 优惠金额,单位:分 + * + * 冗余 {@link CouponTemplateDO#getDiscountPrice()} + */ + private Integer discountPrice; + /** + * 折扣上限,仅在 {@link #discountType} 等于 {@link PromotionDiscountTypeEnum#PERCENT} 时生效 + * + * 冗余 {@link CouponTemplateDO#getDiscountLimitPrice()} + */ + private Integer discountLimitPrice; // ========== 使用效果 END ========== // ========== 使用情况 BEGIN ========== -// /** -// * 使用订单号 -// */ -// private Integer usedOrderId; // TODO 芋艿,暂时不考虑这个字段 -// /** -// * 订单中优惠面值,单位:分 -// */ -// private Integer usedPrice; // TODO 芋艿,暂时不考虑这个字段 + /** + * 使用订单号 + */ + private Long useOrderId; /** * 使用时间 */ - private Date usedTime; - - // TODO 芋艿,后续要加优惠劵的使用日志,因为下单后,可能会取消。 + private Date useTime; // ========== 使用情况 END ========== diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java index 543289c63..f3d545b3e 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/coupon/CouponTemplateDO.java @@ -21,6 +21,8 @@ import java.util.List; * 优惠劵模板 DO * * 当用户领取时,会生成 {@link CouponDO} 优惠劵 + * + * @author 芋道源码 */ @TableName(value = "promotion_coupon_template", autoResultMap = true) @KeySequence("promotion_coupon_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java index aacbc287b..55c924e4f 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/discount/DiscountProductDO.java @@ -1,14 +1,13 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.discount; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; -import java.util.Date; - /** * 限时折扣商品 DO * @@ -31,12 +30,6 @@ public class DiscountProductDO extends BaseDO { * 关联 {@link DiscountActivityDO#getId()} */ private Long activityId; - /** - * 限时折扣活动的名字 - * - * 冗余 {@link DiscountActivityDO#getName()} - */ - private String activityName; /** * 商品 SPU 编号 * @@ -49,23 +42,24 @@ public class DiscountProductDO extends BaseDO { * 关联 ProductSkuDO 的 id 编号 */ private Long skuId; + /** - * 开始时间 - */ - private Date startTime; - /** - * 结束时间 - */ - private Date endTime; - /** - * 销售价格,单位:分 + * 折扣类型 * - * 冗余 ProductSkuDO 的 price 字段 + * 枚举 {@link PromotionDiscountTypeEnum} */ - private Integer originalPrice; + private Integer discountType; /** - * 优惠价格,单位:分 + * 折扣百分比 + * + * 例如,80% 为 80 */ - private Integer promotionPrice; + private Integer discountPercent; + /** + * 优惠金额,单位:分 + * + * 当 {@link #discountType} 为 {@link PromotionDiscountTypeEnum#PRICE} 生效 + */ + private Integer discountPrice; } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java index b284bc939..25e2dd308 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/reward/RewardActivityDO.java @@ -1,6 +1,8 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.reward; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler; import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; @@ -8,10 +10,11 @@ import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import com.baomidou.mybatisplus.extension.handlers.AbstractJsonTypeHandler; import lombok.Data; import lombok.EqualsAndHashCode; +import java.io.Serializable; import java.util.Date; import java.util.List; @@ -68,19 +71,19 @@ public class RewardActivityDO extends BaseDO { /** * 商品 SPU 编号的数组 */ - @TableField(typeHandler = JacksonTypeHandler.class) + @TableField(typeHandler = LongListTypeHandler.class) private List productSpuIds; /** * 优惠规则的数组 */ - @TableField(typeHandler = JacksonTypeHandler.class) + @TableField(typeHandler = RuleTypeHandler.class) private List rules; /** * 优惠规则 */ @Data - public static class Rule { + public static class Rule implements Serializable { /** * 优惠门槛 @@ -112,5 +115,19 @@ public class RewardActivityDO extends BaseDO { } + // TODO @芋艿:可以找一些新的思路 + public static class RuleTypeHandler extends AbstractJsonTypeHandler> { + + @Override + protected List parse(String json) { + return JsonUtils.parseArray(json, Rule.class); + } + + @Override + protected String toJson(List obj) { + return JsonUtils.toJsonString(obj); + } + + } } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java new file mode 100755 index 000000000..d60e75cdb --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponMapper.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; + +/** + * 优惠劵 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface CouponMapper extends BaseMapperX { + + default PageResult selectPage(CouponPageReqVO reqVO, Collection userIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(CouponDO::getTemplateId, reqVO.getTemplateId()) + .eqIfPresent(CouponDO::getStatus, reqVO.getStatus()) + .inIfPresent(CouponDO::getUserId, userIds) + .betweenIfPresent(CouponDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(CouponDO::getId)); + } + + default int delete(Long id, Collection whereStatuses) { + return update(null, new LambdaUpdateWrapper() + .eq(CouponDO::getId, id).in(CouponDO::getStatus, whereStatuses) + .set(CouponDO::getDeleted, 1)); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java index f99e658fb..7cea814af 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/coupon/CouponTemplateMapper.java @@ -3,9 +3,10 @@ package cn.iocoder.yudao.module.promotion.dal.mysql.coupon; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; /** * 优惠劵模板 Mapper @@ -24,4 +25,6 @@ public interface CouponTemplateMapper extends BaseMapperX { .orderByDesc(CouponTemplateDO::getId)); } + void updateTakeCount(@Param("id") Long id, @Param("incrCount") Integer incrCount); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java new file mode 100755 index 000000000..534ce627a --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountActivityMapper.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.discount; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * 限时折扣活动 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface DiscountActivityMapper extends BaseMapperX { + + default PageResult selectPage(DiscountActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(DiscountActivityDO::getName, reqVO.getName()) + .eqIfPresent(DiscountActivityDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(DiscountActivityDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(DiscountActivityDO::getId)); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java new file mode 100755 index 000000000..646b60707 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/DiscountProductMapper.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.discount; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 限时折扣商城 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface DiscountProductMapper extends BaseMapperX { + + default List selectListBySkuId(Collection skuIds) { + return selectList(DiscountProductDO::getSkuId, skuIds); + } + + default List selectListByActivityId(Long activityId) { + return selectList(DiscountProductDO::getActivityId, activityId); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/package-info.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/package-info.java deleted file mode 100644 index 3588ffd83..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/discount/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * TODO 占位 - */ -package cn.iocoder.yudao.module.promotion.dal.mysql.discount; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java new file mode 100755 index 000000000..2ee879823 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/reward/RewardActivityMapper.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.promotion.dal.mysql.reward; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * 满减送活动 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface RewardActivityMapper extends BaseMapperX { + + default PageResult selectPage(RewardActivityPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(RewardActivityDO::getName, reqVO.getName()) + .eqIfPresent(RewardActivityDO::getStatus, reqVO.getStatus()) + .orderByDesc(RewardActivityDO::getId)); + } + + default List selectListByStatus(Collection statuses) { + return selectList(RewardActivityDO::getStatus, statuses); + } + + default List selectListByProductScopeAndStatus(Integer productScope, Integer status) { + return selectList(new LambdaQueryWrapperX() + .eq(RewardActivityDO::getProductScope, productScope) + .eq(RewardActivityDO::getStatus, status)); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java index 7fdac901d..22d5d5cd0 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponService.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.promotion.service.coupon; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; /** @@ -21,4 +23,19 @@ public interface CouponService { */ CouponDO validCoupon(Long id, Long userId); + /** + * 获得优惠劵分页 + * + * @param pageReqVO 分页查询 + * @return 优惠劵分页 + */ + PageResult getCouponPage(CouponPageReqVO pageReqVO); + + /** + * 回收优惠劵 + * + * @param id 优惠劵编号 + */ + void deleteCoupon(Long id); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java index 067bd84bc..3cd3c22c8 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java @@ -1,9 +1,27 @@ package cn.iocoder.yudao.module.promotion.service.coupon; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; +import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.coupon.CouponPageReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponMapper; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import javax.annotation.Resource; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_DELETE_FAIL_USED; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NOT_EXISTS; +import static java.util.Arrays.asList; + /** * 优惠劵 Service 实现类 * @@ -13,9 +31,56 @@ import org.springframework.validation.annotation.Validated; @Validated public class CouponServiceImpl implements CouponService { + @Resource + private CouponTemplateService couponTemplateService; + + @Resource + private CouponMapper couponMapper; + + @Resource + private MemberUserApi memberUserApi; + // TODO 芋艿:待实现 @Override public CouponDO validCoupon(Long id, Long userId) { return null; } + + @Override + public PageResult getCouponPage(CouponPageReqVO pageReqVO) { + // 获得用户编号 + Set userIds = null; + if (StrUtil.isNotEmpty(pageReqVO.getNickname())) { + userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageReqVO.getNickname()), + UserRespDTO::getId); + if (CollUtil.isEmpty(userIds)) { + return PageResult.empty(); + } + } + // 分页查询 + return couponMapper.selectPage(pageReqVO, userIds); + } + + @Override + @Transactional + public void deleteCoupon(Long id) { + // 校验存在 + validateCouponExists(id); + + // 更新优惠劵 + int deleteCount = couponMapper.delete(id, + asList(CouponStatusEnum.UNUSED.getStatus(), CouponStatusEnum.EXPIRE.getStatus())); + if (deleteCount == 0) { + throw exception(COUPON_DELETE_FAIL_USED); + } + // 减少优惠劵模板的领取数量 -1 + couponTemplateService.updateCouponTemplateTakeCount(id, -1); + } + + private void validateCouponExists(Long id) { + if (couponMapper.selectById(id) == null) { + throw exception(COUPON_NOT_EXISTS); + } + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java index a1fc14d13..fdf018974 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateService.java @@ -1,9 +1,9 @@ package cn.iocoder.yudao.module.promotion.service.coupon; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import javax.validation.Valid; @@ -30,6 +30,14 @@ public interface CouponTemplateService { */ void updateCouponTemplate(@Valid CouponTemplateUpdateReqVO updateReqVO); + /** + * 更新优惠劵模板的状态 + * + * @param id 编号 + * @param status 状态 + */ + void updateCouponTemplateStatus(Long id, Integer status); + /** * 删除优惠劵模板 * @@ -53,4 +61,12 @@ public interface CouponTemplateService { */ PageResult getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO); + /** + * 更新优惠劵模板的领取数量 + * + * @param id 优惠劵模板编号 + * @param incrCount 增加数量 + */ + void updateCouponTemplateTakeCount(Long id, int incrCount); + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java index ef7c93db6..1a9cc8bfb 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImpl.java @@ -1,9 +1,10 @@ package cn.iocoder.yudao.module.promotion.service.coupon; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; import cn.iocoder.yudao.module.promotion.convert.coupon.CouponTemplateConvert; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; @@ -30,7 +31,8 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { @Override public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) { // 插入 - CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO); + CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO) + .setStatus(CommonStatusEnum.ENABLE.getStatus()); couponTemplateMapper.insert(couponTemplate); // 返回 return couponTemplate.getId(); @@ -50,6 +52,14 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { couponTemplateMapper.updateById(updateObj); } + @Override + public void updateCouponTemplateStatus(Long id, Integer status) { + // 校验存在 + validateCouponTemplateExists(id); + // 更新 + couponTemplateMapper.updateById(new CouponTemplateDO().setId(id).setStatus(status)); + } + @Override public void deleteCouponTemplate(Long id) { // 校验存在 @@ -76,4 +86,9 @@ public class CouponTemplateServiceImpl implements CouponTemplateService { return couponTemplateMapper.selectPage(pageReqVO); } + @Override + public void updateCouponTemplateTakeCount(Long id, int incrCount) { + couponTemplateMapper.updateTakeCount(id, incrCount); + } + } diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java new file mode 100644 index 000000000..8b6e5895b --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityService.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.promotion.service.discount; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; + +import javax.validation.Valid; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 限时折扣 Service 接口 + * + * @author 芋道源码 + */ +public interface DiscountActivityService { + + /** + * 基于指定 SKU 编号数组,获得匹配的限时折扣商品 + * + * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态 + * + * @param skuIds SKU 编号数组 + * @return 匹配的限时折扣商品 + */ + Map getMatchDiscountProducts(Collection skuIds); + + /** + * 创建限时折扣活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createDiscountActivity(@Valid DiscountActivityCreateReqVO createReqVO); + + /** + * 更新限时折扣活动 + * + * @param updateReqVO 更新信息 + */ + void updateDiscountActivity(@Valid DiscountActivityUpdateReqVO updateReqVO); + + /** + * 关闭限时折扣活动 + * + * @param id 编号 + */ + void closeRewardActivity(Long id); + + /** + * 删除限时折扣活动 + * + * @param id 编号 + */ + void deleteDiscountActivity(Long id); + + /** + * 获得限时折扣活动 + * + * @param id 编号 + * @return 限时折扣活动 + */ + DiscountActivityDO getDiscountActivity(Long id); + + /** + * 获得限时折扣活动分页 + * + * @param pageReqVO 分页查询 + * @return 限时折扣活动分页 + */ + PageResult getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO); + + /** + * 获得活动编号,对应对应的商品列表 + * + * @param activityId 活动编号 + * @return 活动的商品列表 + */ + List getDiscountProductsByActivityId(Long activityId); + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java new file mode 100644 index 000000000..df54d44f2 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImpl.java @@ -0,0 +1,196 @@ +package cn.iocoder.yudao.module.promotion.service.discount; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; +import cn.iocoder.yudao.module.promotion.util.PromotionUtils; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static java.util.Arrays.asList; + +/** + * 限时折扣 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class DiscountActivityServiceImpl implements DiscountActivityService { + + @Resource + private DiscountActivityMapper discountActivityMapper; + @Resource + private DiscountProductMapper discountProductMapper; + + @Override + public Map getMatchDiscountProducts(Collection skuIds) { + List discountProducts = getRewardProductListBySkuIds(skuIds, singleton(PromotionActivityStatusEnum.RUN.getStatus())); + return convertMap(discountProducts, DiscountProductDetailBO::getSkuId); + } + + @Override + public Long createDiscountActivity(DiscountActivityCreateReqVO createReqVO) { + // 校验商品是否冲突 + validateDiscountActivityProductConflicts(null, createReqVO.getProducts()); + + // 插入活动 + DiscountActivityDO discountActivity = DiscountActivityConvert.INSTANCE.convert(createReqVO) + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime())); + discountActivityMapper.insert(discountActivity); + // 插入商品 + List discountProducts = convertList(createReqVO.getProducts(), + product -> DiscountActivityConvert.INSTANCE.convert(product).setActivityId(discountActivity.getId())); + discountProductMapper.insertBatch(discountProducts); + // 返回 + return discountActivity.getId(); + } + + @Override + public void updateDiscountActivity(DiscountActivityUpdateReqVO updateReqVO) { + // 校验存在 + DiscountActivityDO discountActivity = validateDiscountActivityExists(updateReqVO.getId()); + if (discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢 + throw exception(DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); + } + // 校验商品是否冲突 + validateDiscountActivityProductConflicts(updateReqVO.getId(), updateReqVO.getProducts()); + + // 更新活动 + DiscountActivityDO updateObj = DiscountActivityConvert.INSTANCE.convert(updateReqVO) + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime())); + discountActivityMapper.updateById(updateObj); + // 更新商品 + updateDiscountProduct(updateReqVO); + } + + private void updateDiscountProduct(DiscountActivityUpdateReqVO updateReqVO) { + List dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId()); + // 计算要删除的记录 + List deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId, + discountProductDO -> updateReqVO.getProducts().stream() + .noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product))); + if (CollUtil.isNotEmpty(deleteIds)) { + discountProductMapper.deleteBatchIds(deleteIds); + } + // 计算新增的记录 + List newDiscountProducts = convertList(updateReqVO.getProducts(), + product -> DiscountActivityConvert.INSTANCE.convert(product).setActivityId(updateReqVO.getId())); + newDiscountProducts.removeIf(product -> dbDiscountProducts.stream().anyMatch( + dbProduct -> DiscountActivityConvert.INSTANCE.isEquals(dbProduct, product))); // 如果匹配到,说明是更新的 + if (CollectionUtil.isNotEmpty(newDiscountProducts)) { + discountProductMapper.insertBatch(newDiscountProducts); + } + } + + /** + * 校验商品是否冲突 + * + * @param id 编号 + * @param products 商品列表 + */ + private void validateDiscountActivityProductConflicts(Long id, List products) { + if (CollUtil.isEmpty(products)) { + return; + } + // 查询商品参加的活动 + List discountActivityProductList = getRewardProductListBySkuIds( + convertSet(products, DiscountActivityBaseVO.Product::getSkuId), + asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus())); + if (id != null) { // 排除自己这个活动 + discountActivityProductList.removeIf(product -> id.equals(product.getActivityId())); + } + // 如果非空,则说明冲突 + if (CollUtil.isNotEmpty(discountActivityProductList)) { + throw exception(DISCOUNT_ACTIVITY_SPU_CONFLICTS); + } + } + + private List getRewardProductListBySkuIds(Collection skuIds, + Collection statuses) { + // 查询商品 + List products = discountProductMapper.selectListBySkuId(skuIds); + if (CollUtil.isEmpty(products)) { + return new ArrayList<>(0); + } + + // 查询活动 + List activities = discountActivityMapper.selectBatchIds(skuIds); + activities.removeIf(activity -> !statuses.contains(activity.getStatus())); // 移除不满足 statuses 状态的 + Map activityMap = CollectionUtils.convertMap(activities, DiscountActivityDO::getId); + + // 移除不满足活动的商品 + products.removeIf(product -> !activityMap.containsKey(product.getActivityId())); + return DiscountActivityConvert.INSTANCE.convertList(products, activityMap); + } + + @Override + public void closeRewardActivity(Long id) { + // 校验存在 + DiscountActivityDO dbDiscountActivity = validateDiscountActivityExists(id); + if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能关闭噢 + throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); + } + if (dbDiscountActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动,不能关闭噢 + throw exception(DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END); + } + + // 更新 + DiscountActivityDO updateObj = new DiscountActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + discountActivityMapper.updateById(updateObj); + } + + @Override + public void deleteDiscountActivity(Long id) { + // 校验存在 + DiscountActivityDO discountActivity = validateDiscountActivityExists(id); + if (!discountActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动,不能删除噢 + throw exception(DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); + } + + // 删除 + discountActivityMapper.deleteById(id); + } + + private DiscountActivityDO validateDiscountActivityExists(Long id) { + DiscountActivityDO discountActivity = discountActivityMapper.selectById(id); + if (discountActivity == null) { + throw exception(DISCOUNT_ACTIVITY_NOT_EXISTS); + } + return discountActivity; + } + + @Override + public DiscountActivityDO getDiscountActivity(Long id) { + return discountActivityMapper.selectById(id); + } + + @Override + public PageResult getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO) { + return discountActivityMapper.selectPage(pageReqVO); + } + + @Override + public List getDiscountProductsByActivityId(Long activityId) { + return discountProductMapper.selectListByActivityId(activityId); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountService.java deleted file mode 100644 index 9af23898f..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountService.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.iocoder.yudao.module.promotion.service.discount; - -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; - -import java.util.Collection; -import java.util.Map; - -/** - * 限时折扣 Service 接口 - * - * @author 芋道源码 - */ -public interface DiscountService { - - /** - * 基于指定 SKU 编号数组,获得匹配的限时折扣商品 - * - * 注意,匹配的条件,仅仅是日期符合,并且处于开启状态 - * - * @param skuIds SKU 编号数组 - * @return 匹配的限时折扣商品 - */ - Map getMatchDiscountProducts(Collection skuIds); - -} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountServiceImpl.java deleted file mode 100644 index 5b241e010..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountServiceImpl.java +++ /dev/null @@ -1,29 +0,0 @@ -package cn.iocoder.yudao.module.promotion.service.discount; - -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * 限时折扣 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class DiscountServiceImpl implements DiscountService { - - // TODO 芋艿:待实现 - @Override - public Map getMatchDiscountProducts(Collection skuIds) { - Map products = new HashMap<>(); - products.put(1L, new DiscountProductDO().setPromotionPrice(100)); - products.put(2L, new DiscountProductDO().setPromotionPrice(50)); - return products; - } - -} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/bo/DiscountProductDetailBO.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/bo/DiscountProductDetailBO.java new file mode 100644 index 000000000..7b8f4a20f --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/discount/bo/DiscountProductDetailBO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.promotion.service.discount.bo; + +import lombok.Data; + +/** + * 限时折扣活动商品 BO + * + * @author 芋道源码 + */ +@Data +public class DiscountProductDetailBO { + + // ========== DiscountProductDO 字段 ========== + + /** + * 编号,主键自增 + */ + private Long id; + /** + * 限时折扣活动的编号 + */ + private Long activityId; + /** + * 商品 SPU 编号 + */ + private Long spuId; + /** + * 商品 SKU 编号 + */ + private Long skuId; + /** + * 折扣类型 + */ + private Integer discountType; + /** + * 折扣百分比 + */ + private Integer discountPercent; + /** + * 优惠金额,单位:分 + */ + private Integer discountPrice; + + // ========== DiscountActivityDO 字段 ========== + /** + * 活动标题 + */ + private String activityName; + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java index 7fa111d26..062ec2f89 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java +++ b/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; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.*; import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; -import cn.iocoder.yudao.module.promotion.service.discount.DiscountService; -import cn.iocoder.yudao.module.promotion.service.reward.RewardService; -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; import com.google.common.base.Suppliers; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -33,9 +31,8 @@ import java.util.function.Supplier; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_MIN_PRICE; -import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_NO_MATCH_SPU; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static java.util.Collections.singletonList; /** @@ -54,12 +51,13 @@ import static java.util.Collections.singletonList; */ @Service @Validated +@Slf4j public class PriceServiceImpl implements PriceService { @Resource - private DiscountService discountService; + private DiscountActivityService discountService; @Resource - private RewardService rewardService; + private RewardActivityService rewardActivityService; @Resource private CouponService couponService; @@ -79,7 +77,13 @@ public class PriceServiceImpl implements PriceService { calculatePriceForOrderLevel(calculateReqDTO.getUserId(), priceCalculate); // 计算优惠劵级别的价格 calculatePriceForCouponLevel(calculateReqDTO.getUserId(), calculateReqDTO.getCouponId(), priceCalculate); - // 计算【优惠劵】促销 TODO 待实现 + + // 如果最终支付金额小于等于 0,则抛出业务异常 + if (priceCalculate.getOrder().getPayPrice() <= 0) { + log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", + calculateReqDTO, priceCalculate); + throw exception(PRICE_CALCULATE_PAY_PRICE_ILLEGAL); + } return priceCalculate; } @@ -115,24 +119,20 @@ public class PriceServiceImpl implements PriceService { private void calculatePriceForSkuLevel(Long userId, PriceCalculateRespDTO priceCalculate) { // 获取 SKU 级别的所有优惠信息 Supplier memberDiscountPercentSupplier = getMemberDiscountPercentSupplier(userId); - Map discountProducts = discountService.getMatchDiscountProducts( + Map discountProducts = discountService.getMatchDiscountProducts( convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSkuId)); // 处理每个 SKU 的优惠 priceCalculate.getOrder().getItems().forEach(orderItem -> { // 获取该 SKU 的优惠信息 Double memberDiscountPercent = memberDiscountPercentSupplier.get(); - DiscountProductDO discountProduct = discountProducts.get(orderItem.getSkuId()); - if (discountProduct != null // 假设优惠价格更贵,则认为没优惠 - && discountProduct.getPromotionPrice() >= orderItem.getOriginalUnitPrice()) { - discountProduct = null; - } + DiscountProductDetailBO discountProduct = discountProducts.get(orderItem.getSkuId()); if (memberDiscountPercent == null && discountProduct == null) { return; } // 计算价格,判断选择哪个折扣 Integer memberPrice = memberDiscountPercent != null ? (int) (orderItem.getPayPrice() * memberDiscountPercent / 100) : null; - Integer promotionPrice = discountProduct != null ? discountProduct.getPromotionPrice() * orderItem.getCount() : null; + Integer promotionPrice = discountProduct != null ? getDiscountProductPrice(discountProduct, orderItem) : null; if (memberPrice == null) { calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice); } else if (promotionPrice == null) { @@ -145,6 +145,19 @@ public class PriceServiceImpl implements PriceService { }); } + private Integer getDiscountProductPrice(DiscountProductDetailBO discountProduct, + PriceCalculateRespDTO.OrderItem orderItem) { + Integer price = orderItem.getPayPrice(); + if (PromotionDiscountTypeEnum.PRICE.getType().equals(discountProduct.getDiscountType())) { // 减价 + price -= discountProduct.getDiscountPrice() * orderItem.getCount(); + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(discountProduct.getDiscountType())) { // 打折 + price = price * discountProduct.getDiscountPercent() / 100; + } else { + throw new IllegalArgumentException(String.format("优惠活动的商品(%s) 的优惠类型不正确", discountProduct)); + } + return price; + } + private void calculatePriceByMemberDiscount(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, Integer memberPrice) { // 记录优惠明细 @@ -156,7 +169,7 @@ public class PriceServiceImpl implements PriceService { } private void calculatePriceByDiscountActivity(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, - DiscountProductDO discountProduct, Integer promotionPrice) { + DiscountProductDetailBO discountProduct, Integer promotionPrice) { // 记录优惠明细 addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), PromotionLevelEnum.SKU.getLevel(), promotionPrice, @@ -191,7 +204,7 @@ public class PriceServiceImpl implements PriceService { private void calculatePriceForOrderLevel(Long userId, PriceCalculateRespDTO priceCalculate) { // 获取 SKU 级别的所有优惠信息 Set spuIds = convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSpuId); - Map> rewardActivities = rewardService.getMatchRewardActivities(spuIds); + Map> rewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); // 处理满减送活动 if (CollUtil.isNotEmpty(rewardActivities)) { @@ -216,7 +229,6 @@ public class PriceServiceImpl implements PriceService { } // 分摊金额 - // TODO 芋艿:limit 不能超过最大价格 List discountPartPrices = dividePrice(orderItems, rule.getDiscountPrice()); // 记录优惠明细 addPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(), @@ -283,7 +295,7 @@ public class PriceServiceImpl implements PriceService { // 计算是否满足优惠劵的使用金额 Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum); assert originPrice != null; - if (originPrice < coupon.getPriceAvailable()) { + if (originPrice < coupon.getUsePrice()) { throw exception(COUPON_NO_MATCH_MIN_PRICE); } @@ -291,10 +303,9 @@ public class PriceServiceImpl implements PriceService { priceCalculate.getOrder().setCouponId(couponId); Integer couponPrice = getCouponPrice(coupon, originPrice); // 分摊金额 - // TODO 芋艿:limit 不能超过最大价格 List couponPartPrices = dividePrice(orderItems, couponPrice); // 记录优惠明细 - addPromotion(priceCalculate, orderItems, coupon.getId(), coupon.getTitle(), + addPromotion(priceCalculate, orderItems, coupon.getId(), coupon.getName(), PromotionTypeEnum.COUPON.getType(), PromotionLevelEnum.COUPON.getLevel(), couponPartPrices, true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice))); // 修改 SKU 的分摊 @@ -309,19 +320,18 @@ public class PriceServiceImpl implements PriceService { return priceCalculate.getOrder().getItems(); } return CollectionUtils.filterList(priceCalculate.getOrder().getItems(), - orderItem -> coupon.getSpuIds().contains(orderItem.getSpuId())); + orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId())); } private Integer getCouponPrice(CouponDO coupon, Integer originPrice) { - // TODO 芋艿 getPreferentialType 的枚举判断 - if (coupon.getPreferentialType().equals(1)) { // 减价 - return coupon.getPriceOff(); - } else if (coupon.getPreferentialType().equals(2)) { // 打折 - Integer couponPrice = originPrice * coupon.getPercentOff() / 100; - return coupon.getDiscountPriceLimit() == null ? couponPrice - : Math.min(couponPrice, coupon.getDiscountPriceLimit()); // 优惠上限 + if (PromotionDiscountTypeEnum.PRICE.getType().equals(coupon.getDiscountType())) { // 减价 + return coupon.getDiscountPrice(); + } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(coupon.getDiscountType())) { // 打折 + int couponPrice = originPrice * coupon.getDiscountPercent() / 100; + return coupon.getDiscountLimitPrice() == null ? couponPrice + : Math.min(couponPrice, coupon.getDiscountLimitPrice()); // 优惠上限 } - throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon.toString())); + throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", coupon)); } // ========== 其它相对通用的方法 ========== @@ -410,13 +420,16 @@ public class PriceServiceImpl implements PriceService { */ private void modifyOrderItemPayPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer newPayPrice, PriceCalculateRespDTO priceCalculate) { + // diffPayPrice 等于额外增加的商品级的优惠 int diffPayPrice = orderItem.getPayPrice() - newPayPrice; // 设置 OrderItem 价格相关字段 orderItem.setDiscountPrice(orderItem.getDiscountPrice() + diffPayPrice); orderItem.setPayPrice(newPayPrice); orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice()); // 设置 Order 相关相关字段 - priceCalculate.getOrder().setPayPrice(priceCalculate.getOrder().getPayPrice() - diffPayPrice); + PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); + order.setPayPrice(order.getPayPrice() - diffPayPrice); + order.setOrderPrice(order.getOrderPrice() - diffPayPrice); } /** diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java new file mode 100755 index 000000000..40bcc2836 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityService.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.promotion.service.reward; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; + +import javax.validation.Valid; +import java.util.Map; +import java.util.Set; + +/** + * 满减送活动 Service 接口 + * + * @author 芋道源码 + */ +public interface RewardActivityService { + + /** + * 创建满减送活动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRewardActivity(@Valid RewardActivityCreateReqVO createReqVO); + + /** + * 更新满减送活动 + * + * @param updateReqVO 更新信息 + */ + void updateRewardActivity(@Valid RewardActivityUpdateReqVO updateReqVO); + + /** + * 关闭满减送活动 + * + * @param id 活动编号 + */ + void closeRewardActivity(Long id); + + /** + * 删除满减送活动 + * + * @param id 编号 + */ + void deleteRewardActivity(Long id); + + /** + * 获得满减送活动 + * + * @param id 编号 + * @return 满减送活动 + */ + RewardActivityDO getRewardActivity(Long id); + + /** + * 获得满减送活动分页 + * + * @param pageReqVO 分页查询 + * @return 满减送活动分页 + */ + PageResult getRewardActivityPage(RewardActivityPageReqVO pageReqVO); + + /** + * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动 + * + * @param spuIds SPU 编号数组 + * @return 满减送活动,与对应的 SPU 编号的映射。即,value 就是 SPU 编号的集合 + */ + Map> getMatchRewardActivities(Set spuIds); + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java new file mode 100755 index 000000000..51d0ce626 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImpl.java @@ -0,0 +1,169 @@ +package cn.iocoder.yudao.module.promotion.service.reward; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.convert.reward.RewardActivityConvert; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.util.PromotionUtils; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.hutool.core.collection.CollUtil.intersectionDistinct; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; + +/** + * 满减送活动 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class RewardActivityServiceImpl implements RewardActivityService { + + @Resource + private RewardActivityMapper rewardActivityMapper; + + @Override + public Long createRewardActivity(RewardActivityCreateReqVO createReqVO) { + // 校验商品是否冲突 + validateRewardActivitySpuConflicts(null, createReqVO.getProductSpuIds()); + + // 插入 + RewardActivityDO rewardActivity = RewardActivityConvert.INSTANCE.convert(createReqVO) + .setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getStartTime(), createReqVO.getEndTime())); + rewardActivityMapper.insert(rewardActivity); + // 返回 + return rewardActivity.getId(); + } + + @Override + public void updateRewardActivity(RewardActivityUpdateReqVO updateReqVO) { + // 校验存在 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(updateReqVO.getId()); + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢 + throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED); + } + // 校验商品是否冲突 + validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds()); + + // 更新 + RewardActivityDO updateObj = RewardActivityConvert.INSTANCE.convert(updateReqVO) + .setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getStartTime(), updateReqVO.getEndTime())); + rewardActivityMapper.updateById(updateObj); + } + + @Override + public void closeRewardActivity(Long id) { + // 校验存在 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(id); + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能关闭噢 + throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED); + } + if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.END.getStatus())) { // 已关闭的活动,不能关闭噢 + throw exception(REWARD_ACTIVITY_CLOSE_FAIL_STATUS_END); + } + + // 更新 + RewardActivityDO updateObj = new RewardActivityDO().setId(id).setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + rewardActivityMapper.updateById(updateObj); + } + + @Override + public void deleteRewardActivity(Long id) { + // 校验存在 + RewardActivityDO dbRewardActivity = validateRewardActivityExists(id); + if (!dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 未关闭的活动,不能删除噢 + throw exception(REWARD_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED); + } + + // 删除 + rewardActivityMapper.deleteById(id); + } + + private RewardActivityDO validateRewardActivityExists(Long id) { + RewardActivityDO activity = rewardActivityMapper.selectById(id); + if (activity == null) { + throw exception(REWARD_ACTIVITY_NOT_EXISTS); + } + return activity; + } + + /** + * 校验商品参加的活动是否冲突 + * + * @param id 活动编号 + * @param spuIds 商品 SPU 编号数组 + */ + private void validateRewardActivitySpuConflicts(Long id, Collection spuIds) { + if (CollUtil.isEmpty(spuIds)) { + return; + } + // 查询商品参加的活动 + List rewardActivityList = getRewardActivityListBySpuIds(spuIds, + asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus())); + if (id != null) { // 排除自己这个活动 + rewardActivityList.removeIf(activity -> id.equals(activity.getId())); + } + // 如果非空,则说明冲突 + if (CollUtil.isNotEmpty(rewardActivityList)) { + throw exception(REWARD_ACTIVITY_SPU_CONFLICTS); + } + } + + /** + * 获得商品参加的满减送活动的数组 + * + * @param spuIds 商品 SPU 编号数组 + * @param statuses 活动状态数组 + * @return 商品参加的满减送活动的数组 + */ + private List getRewardActivityListBySpuIds(Collection spuIds, + Collection statuses) { + List list = rewardActivityMapper.selectListByStatus(statuses); + return CollUtil.filter(list, activity -> CollUtil.containsAny(activity.getProductSpuIds(), spuIds)); + } + + @Override + public RewardActivityDO getRewardActivity(Long id) { + return rewardActivityMapper.selectById(id); + } + + @Override + public PageResult getRewardActivityPage(RewardActivityPageReqVO pageReqVO) { + return rewardActivityMapper.selectPage(pageReqVO); + } + + @Override + public Map> getMatchRewardActivities(Set spuIds) { + // 如果有全局活动,则直接选择它 + List allActivities = rewardActivityMapper.selectListByProductScopeAndStatus( + PromotionProductScopeEnum.ALL.getScope(), PromotionActivityStatusEnum.RUN.getStatus()); + if (CollUtil.isNotEmpty(allActivities)) { + return MapUtil.builder(allActivities.get(0), spuIds).build(); + } + + // 查询某个活动参加的活动 + List productActivityList = getRewardActivityListBySpuIds(spuIds, + singleton(PromotionActivityStatusEnum.RUN.getStatus())); + return convertMap(productActivityList, activity -> activity, + rewardActivityDO -> intersectionDistinct(rewardActivityDO.getProductSpuIds(), spuIds)); // 求交集返回 + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardService.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardService.java deleted file mode 100644 index ef9123703..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardService.java +++ /dev/null @@ -1,23 +0,0 @@ -package cn.iocoder.yudao.module.promotion.service.reward; - -import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; - -import java.util.Map; -import java.util.Set; - -/** - * 满减送 Service 接口 - * - * @author 芋道源码 - */ -public interface RewardService { - - /** - * 基于指定的 SPU 编号数组,获得它们匹配的满减送活动 - * - * @param spuIds SPU 编号数组 - * @return 满减送活动,与对应的 SPU 编号的映射。即,value 就是 SPU 编号的集合 - */ - Map> getMatchRewardActivities(Set spuIds); - -} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardServiceImpl.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardServiceImpl.java deleted file mode 100644 index af715c4a1..000000000 --- a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/reward/RewardServiceImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.iocoder.yudao.module.promotion.service.reward; - -import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -/** - * 满减送 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -public class RewardServiceImpl implements RewardService { - - // TODO 芋艿:待实现 - @Override - public Map> getMatchRewardActivities(Set spuIds) { - return Collections.emptyMap(); - } - -} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java new file mode 100644 index 000000000..493689661 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/util/PromotionUtils.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.promotion.util; + +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; + +import java.util.Date; + +/** + * 活动工具类 + * + * @author 芋道源码 + */ +public class PromotionUtils { + + /** + * 根据时间,计算活动状态 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 活动状态 + */ + public static Integer calculateActivityStatus(Date startTime, Date endTime) { + if (DateUtils.beforeNow(endTime)) { + return PromotionActivityStatusEnum.END.getStatus(); + } + if (DateUtils.afterNow(startTime)) { + return PromotionActivityStatusEnum.WAIT.getStatus(); + } + return PromotionActivityStatusEnum.RUN.getStatus(); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/coupon/CouponTemplateMapper.xml b/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/coupon/CouponTemplateMapper.xml new file mode 100644 index 000000000..987143534 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/main/resources/mapper/coupon/CouponTemplateMapper.xml @@ -0,0 +1,11 @@ + + + + + + UPDATE promotion_coupon_template + SET take_count = take_count + #{incrCount} + WHERE id = #{id} + + + diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java b/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java index 8a87fb584..fa5510ea2 100755 --- a/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java +++ b/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponTemplateServiceImplTest.java @@ -1,19 +1,24 @@ package cn.iocoder.yudao.module.promotion.service.coupon; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplatePageReqVO; -import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplatePageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateUpdateReqVO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; -import org.junit.jupiter.api.Disabled; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import javax.annotation.Resource; import java.util.Date; +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; @@ -39,7 +44,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest { @Test public void testCreateCouponTemplate_success() { // 准备参数 - CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class); + CouponTemplateCreateReqVO reqVO = randomPojo(CouponTemplateCreateReqVO.class, + o -> o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()) + .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType()) + .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType())); // 调用 Long couponTemplateId = couponTemplateService.createCouponTemplate(reqVO); @@ -58,6 +66,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest { // 准备参数 CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> { o.setId(dbCouponTemplate.getId()); // 设置更新的 ID + // 其它通用字段 + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()) + .setValidityType(randomEle(CouponTemplateValidityTypeEnum.values()).getType()) + .setDiscountType(randomEle(PromotionDiscountTypeEnum.values()).getType()); }); // 调用 @@ -100,30 +112,29 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest { } @Test - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 public void testGetCouponTemplatePage() { // mock 数据 CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class, o -> { // 等会查询到 - o.setName(null); - o.setStatus(null); - o.setDiscountType(null); - o.setCreateTime(null); + o.setName("芋艿"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()); + o.setCreateTime(buildTime(2022, 2, 2)); }); couponTemplateMapper.insert(dbCouponTemplate); // 测试 name 不匹配 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setName(null))); + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setName("土豆"))); // 测试 status 不匹配 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setStatus(null))); + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus()))); // 测试 type 不匹配 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setDiscountType(null))); + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()))); // 测试 createTime 不匹配 - couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setCreateTime(null))); + couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setCreateTime(buildTime(2022, 1, 1)))); // 准备参数 CouponTemplatePageReqVO reqVO = new CouponTemplatePageReqVO(); - reqVO.setName(null); - reqVO.setStatus(null); - reqVO.setDiscountType(null); - reqVO.setCreateTime((new Date[]{})); + reqVO.setName("芋艿"); + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + reqVO.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()); + reqVO.setCreateTime((new Date[]{buildTime(2022, 2, 1), buildTime(2022, 2, 3)})); // 调用 PageResult pageResult = couponTemplateService.getCouponTemplatePage(reqVO); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java b/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java new file mode 100755 index 000000000..c21e622c2 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/discount/DiscountActivityServiceImplTest.java @@ -0,0 +1,209 @@ +package cn.iocoder.yudao.module.promotion.service.discount; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityBaseVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountActivityDO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountActivityMapper; +import cn.iocoder.yudao.module.promotion.dal.mysql.discount.DiscountProductMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.Date; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.DISCOUNT_ACTIVITY_NOT_EXISTS; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link DiscountActivityServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(DiscountActivityServiceImpl.class) +public class DiscountActivityServiceImplTest extends BaseDbUnitTest { + + @Resource + private DiscountActivityServiceImpl discountActivityService; + + @Resource + private DiscountActivityMapper discountActivityMapper; + @Resource + private DiscountProductMapper discountProductMapper; + + @Test + public void testCreateDiscountActivity_success() { + // 准备参数 + DiscountActivityCreateReqVO reqVO = randomPojo(DiscountActivityCreateReqVO.class, o -> { + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + // 设置商品 + o.setProducts(asList(new DiscountActivityBaseVO.Product().setSpuId(1L).setSkuId(2L) + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3), + new DiscountActivityBaseVO.Product().setSpuId(10L).setSkuId(20L) + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30))); + }); + + // 调用 + Long discountActivityId = discountActivityService.createDiscountActivity(reqVO); + // 断言 + assertNotNull(discountActivityId); + // 校验活动 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(discountActivityId); + assertPojoEquals(reqVO, discountActivity); + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + // 校验商品 + List discountProducts = discountProductMapper.selectList(DiscountProductDO::getActivityId, discountActivity.getId()); + assertEquals(discountProducts.size(), reqVO.getProducts().size()); + for (int i = 0; i < reqVO.getProducts().size(); i++) { + DiscountActivityBaseVO.Product product = reqVO.getProducts().get(i); + DiscountProductDO discountProduct = discountProducts.get(i); + assertEquals(discountProduct.getActivityId(), discountActivity.getId()); + assertEquals(discountProduct.getSpuId(), product.getSpuId()); + assertEquals(discountProduct.getSkuId(), product.getSkuId()); + assertEquals(discountProduct.getDiscountType(), product.getDiscountType()); + assertEquals(discountProduct.getDiscountPrice(), product.getDiscountPrice()); + assertEquals(discountProduct.getDiscountPercent(), product.getDiscountPercent()); + } + } + + @Test + public void testUpdateDiscountActivity_success() { + // mock 数据(商品) + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class); + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据 + // mock 数据(活动) + DiscountProductDO dbDiscountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(dbDiscountActivity.getId()) + .setSpuId(1L).setSkuId(2L).setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3).setDiscountPercent(null)); + DiscountProductDO dbDiscountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(dbDiscountActivity.getId()) + .setSpuId(10L).setSkuId(20L).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30).setDiscountPrice(null)); + discountProductMapper.insert(dbDiscountProduct01); + discountProductMapper.insert(dbDiscountProduct02); + // 准备参数 + DiscountActivityUpdateReqVO reqVO = randomPojo(DiscountActivityUpdateReqVO.class, o -> { + o.setId(dbDiscountActivity.getId()); // 设置更新的 ID + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + // 设置商品 + o.setProducts(asList(new DiscountActivityBaseVO.Product().setSpuId(1L).setSkuId(2L) + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(3).setDiscountPercent(null), + new DiscountActivityBaseVO.Product().setSpuId(100L).setSkuId(200L) + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(30).setDiscountPrice(null))); + }); + + // 调用 + discountActivityService.updateDiscountActivity(reqVO); + // 校验活动 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, discountActivity); + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + // 校验商品 + List discountProducts = discountProductMapper.selectList(DiscountProductDO::getActivityId, discountActivity.getId()); + assertEquals(discountProducts.size(), reqVO.getProducts().size()); + for (int i = 0; i < reqVO.getProducts().size(); i++) { + DiscountActivityBaseVO.Product product = reqVO.getProducts().get(i); + DiscountProductDO discountProduct = discountProducts.get(i); + assertEquals(discountProduct.getActivityId(), discountActivity.getId()); + assertEquals(discountProduct.getSpuId(), product.getSpuId()); + assertEquals(discountProduct.getSkuId(), product.getSkuId()); + assertEquals(discountProduct.getDiscountType(), product.getDiscountType()); + assertEquals(discountProduct.getDiscountPrice(), product.getDiscountPrice()); + assertEquals(discountProduct.getDiscountPercent(), product.getDiscountPercent()); + } + } + + @Test + public void testCloseDiscountActivity() { + // mock 数据 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class, + o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDiscountActivity.getId(); + + // 调用 + discountActivityService.closeRewardActivity(id); + // 校验状态 + DiscountActivityDO discountActivity = discountActivityMapper.selectById(id); + assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus()); + } + + @Test + public void testUpdateDiscountActivity_notExists() { + // 准备参数 + DiscountActivityUpdateReqVO reqVO = randomPojo(DiscountActivityUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> discountActivityService.updateDiscountActivity(reqVO), DISCOUNT_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testDeleteDiscountActivity_success() { + // mock 数据 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class, + o -> o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus())); + discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbDiscountActivity.getId(); + + // 调用 + discountActivityService.deleteDiscountActivity(id); + // 校验数据不存在了 + assertNull(discountActivityMapper.selectById(id)); + } + + @Test + public void testDeleteDiscountActivity_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> discountActivityService.deleteDiscountActivity(id), DISCOUNT_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testGetDiscountActivityPage() { + // mock 数据 + DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class, o -> { // 等会查询到 + o.setName("芋艿"); + o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus()); + o.setCreateTime(buildTime(2021, 1, 15)); + }); + discountActivityMapper.insert(dbDiscountActivity); + // 测试 name 不匹配 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setName("土豆"))); + // 测试 status 不匹配 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setStatus(PromotionActivityStatusEnum.END.getStatus()))); + // 测试 createTime 不匹配 + discountActivityMapper.insert(cloneIgnoreId(dbDiscountActivity, o -> o.setCreateTime(buildTime(2021, 2, 10)))); + // 准备参数 + DiscountActivityPageReqVO reqVO = new DiscountActivityPageReqVO(); + reqVO.setName("芋艿"); + reqVO.setStatus(PromotionActivityStatusEnum.WAIT.getStatus()); + reqVO.setCreateTime((new Date[]{buildTime(2021, 1, 1), buildTime(2021, 1, 31)})); + + // 调用 + PageResult pageResult = discountActivityService.getDiscountActivityPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbDiscountActivity, pageResult.getList().get(0)); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java b/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java index 4e4a72738..5263b3404 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java +++ b/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; import cn.hutool.core.map.MapUtil; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; -import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionLevelEnum; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; -import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.*; import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; -import cn.iocoder.yudao.module.promotion.service.discount.DiscountService; -import cn.iocoder.yudao.module.promotion.service.reward.RewardService; -import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; +import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; +import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO; +import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -44,9 +41,9 @@ public class PriceServiceTest extends BaseMockitoUnitTest { private PriceServiceImpl priceService; @Mock - private DiscountService discountService; + private DiscountActivityService discountService; @Mock - private RewardService rewardService; + private RewardActivityService rewardActivityService; @Mock private CouponService couponService; @Mock @@ -67,6 +64,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest { // 断言 Order 部分 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); assertEquals(order.getOriginalPrice(), 200); + assertEquals(order.getOrderPrice(), 180); assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getPointPrice(), 0); assertEquals(order.getDeliveryPrice(), 0); @@ -112,22 +110,28 @@ public class PriceServiceTest extends BaseMockitoUnitTest { ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50)); when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02)); // mock 方法(限时折扣 DiscountActivity 信息) - DiscountProductDO discountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(1000L).setActivityName("活动 1000 号") - .setSkuId(10L).setPromotionPrice(80)); - DiscountProductDO discountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(2000L).setActivityName("活动 2000 号") - .setSkuId(20L).setPromotionPrice(40)); + DiscountProductDetailBO discountProduct01 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(1000L) + .setActivityName("活动 1000 号").setSkuId(10L) + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(40)); + DiscountProductDetailBO discountProduct02 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(2000L) + .setActivityName("活动 2000 号").setSkuId(20L) + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(60)); when(discountService.getMatchDiscountProducts(eq(asSet(10L, 20L)))).thenReturn( MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map()); + // 10L: 100 * 2 - 40 * 2 = 120 + // 20L:50 * 3 - 50 * 3 * 0.4 = 90 + // 调用 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); // 断言 Order 部分 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); assertEquals(order.getOriginalPrice(), 350); + assertEquals(order.getOrderPrice(), 210); assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getPointPrice(), 0); assertEquals(order.getDeliveryPrice(), 0); - assertEquals(order.getPayPrice(), 280); + assertEquals(order.getPayPrice(), 210); assertNull(order.getCouponId()); // 断言 OrderItem 部分 assertEquals(order.getItems().size(), 2); @@ -136,19 +140,19 @@ public class PriceServiceTest extends BaseMockitoUnitTest { assertEquals(orderItem01.getCount(), 2); assertEquals(orderItem01.getOriginalPrice(), 200); assertEquals(orderItem01.getOriginalUnitPrice(), 100); - assertEquals(orderItem01.getDiscountPrice(), 40); - assertEquals(orderItem01.getPayPrice(), 160); + assertEquals(orderItem01.getDiscountPrice(), 80); + assertEquals(orderItem01.getPayPrice(), 120); assertEquals(orderItem01.getOrderPartPrice(), 0); - assertEquals(orderItem01.getOrderDividePrice(), 160); + assertEquals(orderItem01.getOrderDividePrice(), 120); PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1); assertEquals(orderItem02.getSkuId(), 20L); assertEquals(orderItem02.getCount(), 3); assertEquals(orderItem02.getOriginalPrice(), 150); assertEquals(orderItem02.getOriginalUnitPrice(), 50); - assertEquals(orderItem02.getDiscountPrice(), 30); - assertEquals(orderItem02.getPayPrice(), 120); + assertEquals(orderItem02.getDiscountPrice(), 60); + assertEquals(orderItem02.getPayPrice(), 90); assertEquals(orderItem02.getOrderPartPrice(), 0); - assertEquals(orderItem02.getOrderDividePrice(), 120); + assertEquals(orderItem02.getOrderDividePrice(), 90); // 断言 Promotion 部分 assertEquals(priceCalculate.getPromotions().size(), 2); PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0); @@ -157,28 +161,28 @@ public class PriceServiceTest extends BaseMockitoUnitTest { assertEquals(promotion01.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); assertEquals(promotion01.getLevel(), PromotionLevelEnum.SKU.getLevel()); assertEquals(promotion01.getOriginalPrice(), 200); - assertEquals(promotion01.getDiscountPrice(), 40); + assertEquals(promotion01.getDiscountPrice(), 80); assertTrue(promotion01.getMeet()); - assertEquals(promotion01.getMeetTip(), "限时折扣:省 0.40 元"); + assertEquals(promotion01.getMeetTip(), "限时折扣:省 0.80 元"); PriceCalculateRespDTO.PromotionItem promotionItem01 = promotion01.getItems().get(0); assertEquals(promotion01.getItems().size(), 1); assertEquals(promotionItem01.getSkuId(), 10L); assertEquals(promotionItem01.getOriginalPrice(), 200); - assertEquals(promotionItem01.getDiscountPrice(), 40); + assertEquals(promotionItem01.getDiscountPrice(), 80); PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1); assertEquals(promotion02.getId(), 2000L); assertEquals(promotion02.getName(), "活动 2000 号"); assertEquals(promotion02.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); assertEquals(promotion02.getLevel(), PromotionLevelEnum.SKU.getLevel()); assertEquals(promotion02.getOriginalPrice(), 150); - assertEquals(promotion02.getDiscountPrice(), 30); + assertEquals(promotion02.getDiscountPrice(), 60); assertTrue(promotion02.getMeet()); - assertEquals(promotion02.getMeetTip(), "限时折扣:省 0.30 元"); + assertEquals(promotion02.getMeetTip(), "限时折扣:省 0.60 元"); PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0); assertEquals(promotion02.getItems().size(), 1); assertEquals(promotionItem02.getSkuId(), 20L); assertEquals(promotionItem02.getOriginalPrice(), 150); - assertEquals(promotionItem02.getDiscountPrice(), 30); + assertEquals(promotionItem02.getDiscountPrice(), 60); } /** @@ -208,13 +212,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest { Map> matchRewardActivities = new LinkedHashMap<>(); matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); matchRewardActivities.put(rewardActivity02, asSet(3L)); - when(rewardService.getMatchRewardActivities(eq(asSet(1L, 2L, 3L)))).thenReturn(matchRewardActivities); + when(rewardActivityService.getMatchRewardActivities(eq(asSet(1L, 2L, 3L)))).thenReturn(matchRewardActivities); // 调用 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); // 断言 Order 部分 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); assertEquals(order.getOriginalPrice(), 470); + assertEquals(order.getOrderPrice(), 470); assertEquals(order.getDiscountPrice(), 130); assertEquals(order.getPointPrice(), 0); assertEquals(order.getDeliveryPrice(), 0); @@ -305,13 +310,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest { .setRules(singletonList(new RewardActivityDO.Rule().setLimit(351).setDiscountPrice(70)))); Map> matchRewardActivities = new LinkedHashMap<>(); matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); - when(rewardService.getMatchRewardActivities(eq(asSet(1L, 2L)))).thenReturn(matchRewardActivities); + when(rewardActivityService.getMatchRewardActivities(eq(asSet(1L, 2L)))).thenReturn(matchRewardActivities); // 调用 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); // 断言 Order 部分 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); assertEquals(order.getOriginalPrice(), 350); + assertEquals(order.getOrderPrice(), 350); assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getPointPrice(), 0); assertEquals(order.getDeliveryPrice(), 0); @@ -373,19 +379,18 @@ public class PriceServiceTest extends BaseMockitoUnitTest { ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L)); when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03)); // mock 方法(优惠劵 Coupon 信息) - CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setTitle("程序员节") - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setSpuIds(asList(1L, 2L)) - .setPriceAvailable(350).setPreferentialType(2).setPercentOff(50).setDiscountPriceLimit(70)); + CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setName("程序员节") + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L)) + .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()) + .setDiscountPercent(50).setDiscountLimitPrice(70)); when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon); - // 200 + 150; 350 - // - // 调用 PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); // 断言 Order 部分 PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); assertEquals(order.getOriginalPrice(), 470); + assertEquals(order.getOrderPrice(), 470); assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getPointPrice(), 0); assertEquals(order.getDeliveryPrice(), 0); diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java b/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java new file mode 100755 index 000000000..5f9e0cca1 --- /dev/null +++ b/yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/reward/RewardActivityServiceImplTest.java @@ -0,0 +1,218 @@ +package cn.iocoder.yudao.module.promotion.service.reward; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityCreateReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityPageReqVO; +import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivityUpdateReqVO; +import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; +import cn.iocoder.yudao.module.promotion.dal.mysql.reward.RewardActivityMapper; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; +import java.util.Map; +import java.util.Set; + +import static cn.hutool.core.util.RandomUtil.randomEle; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.REWARD_ACTIVITY_NOT_EXISTS; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.*; + +/** +* {@link RewardActivityServiceImpl} 的单元测试类 +* +* @author 芋道源码 +*/ +@Import(RewardActivityServiceImpl.class) +public class RewardActivityServiceImplTest extends BaseDbUnitTest { + + @Resource + private RewardActivityServiceImpl rewardActivityService; + + @Resource + private RewardActivityMapper rewardActivityMapper; + + @Test + public void testCreateRewardActivity_success() { + // 准备参数 + RewardActivityCreateReqVO reqVO = randomPojo(RewardActivityCreateReqVO.class, o -> { + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType()); + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()); + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + }); + + // 调用 + Long rewardActivityId = rewardActivityService.createRewardActivity(reqVO); + // 断言 + assertNotNull(rewardActivityId); + // 校验记录的属性是否正确 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(rewardActivityId); + assertPojoEquals(reqVO, rewardActivity, "rules"); + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + for (int i = 0; i < reqVO.getRules().size(); i++) { + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i)); + } + } + + @Test + public void testUpdateRewardActivity_success() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class, o -> { + o.setId(dbRewardActivity.getId()); // 设置更新的 ID + o.setConditionType(randomEle(PromotionConditionTypeEnum.values()).getType()); + o.setProductScope(randomEle(PromotionProductScopeEnum.values()).getScope()); + // 用于触发进行中的状态 + o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2))); + }); + + // 调用 + rewardActivityService.updateRewardActivity(reqVO); + // 校验是否更新正确 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, rewardActivity, "rules"); + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.WAIT.getStatus()); + for (int i = 0; i < reqVO.getRules().size(); i++) { + assertPojoEquals(reqVO.getRules().get(i), rewardActivity.getRules().get(i)); + } + } + + @Test + public void testCloseRewardActivity() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.WAIT.getStatus())); + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbRewardActivity.getId(); + + // 调用 + rewardActivityService.closeRewardActivity(id); + // 校验状态 + RewardActivityDO rewardActivity = rewardActivityMapper.selectById(id); + assertEquals(rewardActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus()); + } + + @Test + public void testUpdateRewardActivity_notExists() { + // 准备参数 + RewardActivityUpdateReqVO reqVO = randomPojo(RewardActivityUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> rewardActivityService.updateRewardActivity(reqVO), REWARD_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testDeleteRewardActivity_success() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus())); + rewardActivityMapper.insert(dbRewardActivity);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbRewardActivity.getId(); + + // 调用 + rewardActivityService.deleteRewardActivity(id); + // 校验数据不存在了 + assertNull(rewardActivityMapper.selectById(id)); + } + + @Test + public void testDeleteRewardActivity_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> rewardActivityService.deleteRewardActivity(id), REWARD_ACTIVITY_NOT_EXISTS); + } + + @Test + public void testGetRewardActivityPage() { + // mock 数据 + RewardActivityDO dbRewardActivity = randomPojo(RewardActivityDO.class, o -> { // 等会查询到 + o.setName("芋艿"); + o.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + }); + rewardActivityMapper.insert(dbRewardActivity); + // 测试 name 不匹配 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setName("土豆"))); + // 测试 status 不匹配 + rewardActivityMapper.insert(cloneIgnoreId(dbRewardActivity, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()))); + // 准备参数 + RewardActivityPageReqVO reqVO = new RewardActivityPageReqVO(); + reqVO.setName("芋艿"); + reqVO.setStatus(PromotionActivityStatusEnum.CLOSE.getStatus()); + + // 调用 + PageResult pageResult = rewardActivityService.getRewardActivityPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbRewardActivity, pageResult.getList().get(0), "rules"); + } + + @Test + public void testGetRewardActivities_all() { + // mock 数据 + RewardActivityDO allActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.ALL.getScope())); + rewardActivityMapper.insert(allActivity); + RewardActivityDO productActivity = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))); + rewardActivityMapper.insert(productActivity); + // 准备参数 + Set spuIds = asSet(1L, 2L); + + // 调用 + Map> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); + // 断言 + assertEquals(matchRewardActivities.size(), 1); + Map.Entry> next = matchRewardActivities.entrySet().iterator().next(); + assertPojoEquals(next.getKey(), allActivity); + assertEquals(next.getValue(), spuIds); + } + + @Test + public void testGetRewardActivities_product() { + // mock 数据 + RewardActivityDO productActivity01 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))); + rewardActivityMapper.insert(productActivity01); + RewardActivityDO productActivity02 = randomPojo(RewardActivityDO.class, o -> o.setStatus(PromotionActivityStatusEnum.RUN.getStatus()) + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(singletonList(3L))); + rewardActivityMapper.insert(productActivity02); + // 准备参数 + Set spuIds = asSet(1L, 2L, 3L); + + // 调用 + Map> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds); + // 断言 + assertEquals(matchRewardActivities.size(), 2); + matchRewardActivities.forEach((activity, activitySpuIds) -> { + if (activity.getId().equals(productActivity01.getId())) { + assertPojoEquals(activity, productActivity01); + assertEquals(activitySpuIds, asSet(1L, 2L)); + } else if (activity.getId().equals(productActivity02.getId())) { + assertPojoEquals(activity, productActivity02); + assertEquals(activitySpuIds, asSet(3L)); + } else { + fail(); + } + }); + } + +} diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql b/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql index abad7c069..d3f8e3718 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql +++ b/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/clean.sql @@ -1 +1,6 @@ DELETE FROM "market_activity"; +DELETE FROM "promotion_coupon_template"; +DELETE FROM "promotion_coupon"; +DELETE FROM "promotion_reward_activity"; +DELETE FROM "promotion_discount_activity"; +DELETE FROM "promotion_discount_product"; diff --git a/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql b/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql index 3f3ce3c4d..7ff1a7239 100644 --- a/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql +++ b/yudao-module-mall/yudao-module-promotion-biz/src/test/resources/sql/create_tables.sql @@ -16,4 +16,109 @@ CREATE TABLE IF NOT EXISTS "market_activity" ( "deleted" bit NOT NULL DEFAULT FALSE, "tenant_id" bigint(20) NOT NULL, PRIMARY KEY ("id") - ) COMMENT '促销活动'; \ No newline at end of file + ) COMMENT '促销活动'; + +CREATE TABLE IF NOT EXISTS "promotion_coupon_template" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "status" int NOT NULL, + "total_count" int NOT NULL, + "take_limit_count" int NOT NULL, + "take_type" int NOT NULL, + "use_price" int NOT NULL, + "product_scope" int NOT NULL, + "product_spu_ids" varchar, + "validity_type" int NOT NULL, + "valid_start_time" datetime, + "valid_end_time" datetime, + "fixed_start_term" int, + "fixed_end_term" int, + "discount_type" int NOT NULL, + "discount_percent" int, + "discount_price" int, + "discount_limit_price" int, + "take_count" int NOT NULL DEFAULT 0, + "use_count" int NOT NULL DEFAULT 0, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '优惠劵模板'; + +CREATE TABLE IF NOT EXISTS "promotion_coupon" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "template_id" bigint NOT NULL, + "name" varchar NOT NULL, + "status" int NOT NULL, + "user_id" bigint NOT NULL, + "take_type" int NOT NULL, + "useprice" int NOT NULL, + "valid_start_time" datetime NOT NULL, + "valid_end_time" datetime NOT NULL, + "product_scope" int NOT NULL, + "product_spu_ids" varchar, + "discount_type" int NOT NULL, + "discount_percent" int, + "discount_price" int, + "discount_limit_price" int, + "use_order_id" bigint, + "use_time" datetime, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '优惠劵'; + +CREATE TABLE IF NOT EXISTS "promotion_reward_activity" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "status" int NOT NULL, + "start_time" datetime NOT NULL, + "end_time" datetime NOT NULL, + "remark" varchar, + "condition_type" int NOT NULL, + "product_scope" int NOT NULL, + "product_spu_ids" varchar, + "rules" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '满减送活动'; + +CREATE TABLE IF NOT EXISTS "promotion_discount_activity" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "name" varchar NOT NULL, + "status" int NOT NULL, + "start_time" datetime NOT NULL, + "end_time" datetime NOT NULL, + "remark" varchar, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '限时折扣活动'; + +CREATE TABLE IF NOT EXISTS "promotion_discount_product" ( + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, + "activity_id" bigint NOT NULL, + "spu_id" bigint NOT NULL, + "sku_id" bigint NOT NULL, + "discount_type" int NOT NULL, + "discount_percent" int, + "discount_price" int, + "creator" varchar DEFAULT '', + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updater" varchar DEFAULT '', + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + "deleted" bit NOT NULL DEFAULT FALSE, + PRIMARY KEY ("id") +) COMMENT '限时折扣活动'; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java index 2d600a314..802127b26 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java @@ -43,13 +43,12 @@ public class AppTradeOrderController { @PreAuthenticated public CommonResult createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, HttpServletRequest servletRequest) { - // 获取登录用户 + // 获取登录用户、用户 IP 地址 Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); - // 获取用户ip地址 String clientIp = ServletUtil.getClientIP(servletRequest); // 创建交易订单,预支付记录 - Long result = tradeOrderService.createTradeOrder(loginUserId, clientIp, createReqVO); - return CommonResult.success(result); + Long orderId = tradeOrderService.createTradeOrder(loginUserId, clientIp, createReqVO); + return CommonResult.success(orderId); } @GetMapping("/get") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java index 54e856a6b..54629e543 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java +++ b/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 { @ApiModelProperty(name = "优惠劵编号", example = "1024") private Long couponId; - @ApiModelProperty(name = "备注", example = "1024") + @ApiModelProperty(name = "备注", example = "这个是我的订单哟") private String remark; @ApiModelProperty(name = "是否来自购物车", required = true, example = "true", notes = "true - 来自购物车;false - 立即购买") diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java index 0cbd7021c..defd64f98 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderDO.java +++ b/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; import cn.iocoder.yudao.framework.common.enums.TerminalEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO.OrderItem; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderCancelTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; @@ -74,7 +75,7 @@ public class TradeOrderDO extends BaseDO { /** * 购买的商品数量 */ - private Integer productCount; // total_num + private Integer productCount; /** * 订单完成时间 */ @@ -116,14 +117,25 @@ public class TradeOrderDO extends BaseDO { * 商品原价(总),单位:分 * * 基于 {@link TradeOrderItemDO#getTotalOriginalPrice()} 求和 + * + * 对应 taobao 的 trade.total_fee 字段 */ private Integer originalPrice; + /** + * 订单原价(总),单位:分 + * + * 基于 {@link OrderItem#getPayPrice()} 求和 + * 和 {@link #originalPrice} 的差异:去除商品级优惠 + */ + private Integer orderPrice; /** * 订单优惠(总),单位:分 * - * 例如说:满减折扣;不包括优惠劵、商品优惠(TODO) + * 订单级优惠:对主订单的优惠,常见如:订单满 200 元减 10 元;订单满 80 包邮。 + * + * 对应 taobao 的 order.discount_fee 字段 */ - private Integer promotionPrice; + private Integer discountPrice; /** * 运费金额,单位:分 */ @@ -137,12 +149,12 @@ public class TradeOrderDO extends BaseDO { /** * 应付金额(总),单位:分 * - * = {@link #originalPrice} - * + {@link #deliveryPrice} - * + {@link #adjustPrice} - * - {@link #promotionPrice} + * = {@link OrderItem#getPayPrice()} 求和 * - {@link #couponPrice} * - {@link #pointPrice} + * + {@link #deliveryPrice} + * - {@link #discountPrice} + * + {@link #adjustPrice} */ private Integer payPrice; /** @@ -164,11 +176,11 @@ public class TradeOrderDO extends BaseDO { * * 关联 DeliveryTemplateDO 的 id 编号 */ - private Long deliveryTemplateId; // dvy_id + private Long deliveryTemplateId; /** * 物流公司单号 */ - private String expressNo; // dvy_flow_id + private String expressNo; /** * 发货状态 * @@ -227,10 +239,14 @@ public class TradeOrderDO extends BaseDO { private Long couponId; /** * 优惠劵减免金额,单位:分 + * + * 对应 taobao 的 trade.coupon_fee 字段 */ private Integer couponPrice; /** * 积分抵扣的金额,单位:分 + * + * 对应 taobao 的 trade.point_fee 字段 */ private Integer pointPrice; diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java index 14e4de0f4..4ee710ef0 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java +++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java @@ -71,7 +71,7 @@ public class TradeOrderItemDO extends BaseDO { */ private Integer count; /** - * 是否评论 + * 是否评论 TODO * * false - 未评论 * true - 已评论 @@ -79,61 +79,61 @@ public class TradeOrderItemDO extends BaseDO { private Boolean commented; // ========== 价格 + 支付基本信息 ========== + + /** + * 商品原价(总),单位:分 + * + * = {@link #originalUnitPrice} * {@link #getCount()} + */ + private Integer originalPrice; /** * 商品原价(单),单位:分 * * 对应 ProductSkuDO 的 price 字段 + * 对应 taobao 的 order.price 字段 */ - // like - original_price;niu - costPrice - private Integer originalPrice; + private Integer originalUnitPrice; /** - * 商品原价(总),单位:分 + * 商品优惠(总),单位:分 * - * = {@link #originalPrice} * {@link #count} - */ - // like - total_price;niu - 暂无 - private Integer totalOriginalPrice; - /** - * 商品级优惠(总),单位:分 + * 商品级优惠:对单个商品的,常见如:商品原价的 8 折;商品原价的减 50 元 * - * 例如说“限时折扣”:商品原价的 8 折;商品原价的减 50 元 + * 对应 taobao 的 order.discount_fee 字段 */ - // taobao - order.discount_fee(子订单商品优惠) - private Integer totalPromotionPrice; + private Integer discountPrice; /** - * 最终购买金额(单),单位:分。 + * 子订单实付金额,不算主订单分摊金额,单位:分 * - * = {@link #totalPresentPrice} / {@link #count} - */ - private Integer presentPrice; - /** - * 最终购买金额(总),单位:分。 + * = {@link #originalPrice} + * - {@link #discountPrice} * - * = {@link #totalOriginalPrice} - * - {@link #totalPromotionPrice} + * 对应 taobao 的 order.payment 字段 */ - // like - total_pay_price;niu - goods_money; taobao - order.payment(子订单实付金额,不算主订单分摊金额) | order.total_fee(子订单应付金额,参考使用) - private Integer totalPresentPrice; - // TODO 芋艿:part_mjz_discount(子订单分摊金额);本质上,totalOriginalPrice - totalPayPrice + private Integer payPrice; + /** - * 应付金额(总),单位:分 + * 子订单分摊金额(总),单位:分 + * 需要分摊 {@link TradeOrderDO#getDiscountPrice()}、{@link TradeOrderDO#getCouponPrice()}、{@link TradeOrderDO#getPointPrice()} + * + * 对应 taobao 的 order.part_mjz_discount 字段 + * 淘宝说明:子订单分摊优惠基础逻辑:一般正常优惠券和满减优惠按照子订单的金额进行分摊,特殊情况如果优惠券是指定商品使用的,只会分摊到对应商品子订单上不分摊。 */ - // taobao - divide_order_fee (分摊后子订单实付金额); - private Integer totalPayPrice; + private Integer orderPartPrice; + /** + * 分摊后子订单实付金额(总),单位:分 + * + * = {@link #payPrice} + * - {@link #orderPartPrice} + * + * 对应 taobao 的 divide_order_fee 字段 + */ + private Integer orderDividePrice; // ========== 营销基本信息 ========== -// /** -// * 积分抵扣的金额,单位:分 -// */ -// private Integer integralTotal; // like - integral_price;niu - point_money -// /** -// * 使用的积分 -// */ -// private Integer useIntegral; // niu - use_point // ========== 退款基本信息 ========== /** - * 退款状态 + * 退款状态 TODO * * 枚举 {@link TradeOrderItemRefundStatusEnum} */ @@ -148,7 +148,7 @@ public class TradeOrderItemDO extends BaseDO { // presentTotal = buyTotal - discountTotal = 24 - 11 = 13 // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 /** - * 退款总金额,单位:分 + * 退款总金额,单位:分 TODO */ private Integer refundTotal; @@ -173,42 +173,5 @@ public class TradeOrderItemDO extends BaseDO { } - // TODO 芋艿:basket_date 加入购物车时间; - // TODO 芋艿:distribution_card_no 推广员使用的推销卡号 - - // TODO 待确定:mf - // TODO give_integral:赠送积分 - // TODO is_reply:是否评价,0-未评价,1-已评价 - // TODO is_sub:是否单独分佣,0-否,1-是 - // TODO vip_price:会员价 - // TODO product_type:商品类型:0-普通,1-秒杀,2-砍价,3-拼团,4-视频号 - - // TODO 待确定:lf - // TODO integral_price:积分抵扣的金额 - // TODO member_price:会员价格 - // TODO is_member:是否为会员折扣;0-不是;1-是 - // TODO member_discount:会员折扣(百分比) - - // TODO goods_info 商品信息 - - // TODO integral_price:积分抵扣的金额 - - // TODO 待确定:niu - // TODO is_virtual '是否是虚拟商品' - // TODO goods_class '商品种类(1.实物 2.虚拟3.卡券)' - // TODO adjust_money ''调整金额'' - - // TODO is_fenxiao 是否分销, - // TODO adjust_money 是否分销, - - // TODO delivery_status '配送状态' - // TODO delivery_no ''配送单号'' - // TODO gift_flag '赠品标识' - // TODO gift_flag '赠品标识' - - // TODO refund_status '退款状态' - // TODO refund_type '退款状态' - // TODO 一堆退款字段 - } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java index c70a2a273..572a654ba 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderService.java +++ b/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; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; /** - * TODO @LeeYan9: 类注释 + * 交易订单 Service 接口 + * * @author LeeYan9 * @since 2022-08-26 */ public interface TradeOrderService { /** - * 创建交易订单 TODO @LeeYan9: 方法注释, 和参数要空一行 + * 创建交易订单 + * * @param loginUserId 登录用户 - * @param clientIp 用户ip地址 // TODO @LeeYan9: 中英文之间, 空一行哈 + * @param clientIp 用户 IP 地址 * @param createReqVO 创建交易订单请求模型 - * @return 交易订单创建结果 + * @return 交易订单的编号 */ Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO); } diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java index ecab7d9fd..9b7b877fa 100644 --- a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java +++ b/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; import java.util.Objects; /** - * TODO @LeeYan9: 注释 + * 交易订单 Service 实现类 + * * @author LeeYan9 * @since 2022-08-26 */ @Service public class TradeOrderServiceImpl implements TradeOrderService { - // TODO @LeeYan9: 相同类型的, 可以放在一起,不用空行; 例如说 Mapper 和 API 和 Properties + // TODO LeeYan9: 静态变量, 需要在最前面哈; 另外, 静态变量的注释最好写下; + private static final String BLANK_PLACEHOLDER = " "; + private static final String MULTIPLIER_PLACEHOLDER = "x"; @Resource private TradeOrderMapper tradeOrderMapper; @@ -71,15 +74,10 @@ public class TradeOrderServiceImpl implements TradeOrderService { @Resource private TradeOrderProperties tradeOrderProperties; - // TODO LeeYan9: 静态变量, 需要在最前面哈; 另外, 静态变量的注释最好写下; - private static final String BLANK_PLACEHOLDER = " "; - private static final String MULTIPLIER_PLACEHOLDER = "x"; - @Override @Transactional(rollbackFor = Exception.class) public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { - - List items = createReqVO.getItems(); // TODO @LeeYan9: 方法第一行, 不用空哈; + List items = createReqVO.getItems(); // 商品SKU检查 sku可售状态,库存 List skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId)); Map skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId); diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java index c6c37f935..235ebb2c4 100644 --- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApi.java +++ b/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; import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + /** * 会员用户的 API 接口 * @@ -17,4 +23,30 @@ public interface MemberUserApi { */ UserRespDTO getUser(Long id); + /** + * 获得会员用户信息们 + * + * @param ids 用户编号的数组 + * @return 用户信息们 + */ + List getUsers(Collection ids); + + /** + * 获得会员用户 Map + * + * @param ids 用户编号的数组 + * @return 会员用户 Map + */ + default Map getUserMap(Collection ids) { + return convertMap(getUsers(ids), UserRespDTO::getId); + } + + /** + * 基于用户昵称,模糊匹配用户列表 + * + * @param nickname 用户昵称,模糊匹配 + * @return 用户信息的列表 + */ + List getUserListByNickname(String nickname); + } diff --git a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserInfoDTO.java b/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserInfoDTO.java deleted file mode 100644 index a814edad0..000000000 --- a/yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/user/dto/UserInfoDTO.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.member.api.user.dto; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import lombok.Data; - -import java.util.Date; - -/** - * 用户信息 Response DTO - * - * @author 芋道源码 - */ -@Data -public class UserInfoDTO { - - /** - * 用户ID - */ - private Long id; - /** - * 用户昵称 - */ - private String nickname; - /** - * 用户头像 - */ - private String avatar; - /** - * 帐号状态 - * - * 枚举 {@link CommonStatusEnum} - */ - private Integer status; - - /** - * 手机 - */ - private String mobile; - /** - * 注册 IP - */ - private String registerIp; - /** - * 最后登录IP - */ - private String loginIp; - /** - * 最后登录时间 - */ - private Date loginDate; - -} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java index 35e7b51ce..0c3e616a0 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/user/MemberUserApiImpl.java +++ b/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; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; /** * 会员用户的 API 实现类 @@ -27,4 +29,14 @@ public class MemberUserApiImpl implements MemberUserApi { return UserConvert.INSTANCE.convert2(user); } + @Override + public List getUsers(Collection ids) { + return UserConvert.INSTANCE.convertList2(userService.getUserList(ids)); + } + + @Override + public List getUserListByNickname(String nickname) { + return UserConvert.INSTANCE.convertList2(userService.getUserListByNickname(nickname)); + } + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/UserController.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/UserController.java deleted file mode 100644 index 795c8162c..000000000 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/admin/user/UserController.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.iocoder.yudao.module.member.controller.admin.user; - -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.member.api.user.dto.UserInfoDTO; -import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; -import cn.iocoder.yudao.module.member.convert.user.UserConvert; -import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; -import cn.iocoder.yudao.module.member.service.user.MemberUserService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; - -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; - -/** - * @author Banging - */ -@Slf4j -@Api("用户管理") -@RestController(value = "memberUserController") -@RequestMapping("/user") -public class UserController { - - @Resource - private MemberUserService userService; - - @ApiOperation(value = "用户信息获取",notes = "用户基本信息的获取") - @GetMapping("/{tel}") - public CommonResult getUserInfo(@PathVariable String tel){ - MemberUserDO user = userService.getUserByMobile(tel); - return CommonResult.success(UserConvert.INSTANCE.convertInfo(user)); - } -} diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java index 6be0d6b41..c2128c104 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/user/UserConvert.java @@ -1,12 +1,13 @@ package cn.iocoder.yudao.module.member.convert.user; -import cn.iocoder.yudao.module.member.api.user.dto.UserInfoDTO; import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; +import java.util.List; + @Mapper public interface UserConvert { @@ -15,5 +16,7 @@ public interface UserConvert { AppUserInfoRespVO convert(MemberUserDO bean); UserRespDTO convert2(MemberUserDO bean); - UserInfoDTO convertInfo(MemberUserDO bean); + + List convertList2(List list); + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java index 9ba09a111..5e63aae36 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/user/MemberUserMapper.java @@ -1,9 +1,12 @@ package cn.iocoder.yudao.module.member.dal.mysql.user; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * 会员 User Mapper * @@ -16,4 +19,9 @@ public interface MemberUserMapper extends BaseMapperX { return selectOne(MemberUserDO::getMobile, mobile); } + default List selectListByNicknameLike(String nickname) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(MemberUserDO::getNickname, nickname)); + } + } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java index 3b63c8d71..da3b4fd4a 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserService.java +++ b/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 import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import java.io.InputStream; +import java.util.Collection; +import java.util.List; /** * 会员用户 Service 接口 @@ -21,6 +23,15 @@ public interface MemberUserService { */ MemberUserDO getUserByMobile(String mobile); + /** + * 基于用户昵称,模糊匹配用户列表 + * + * @param nickname 用户昵称,模糊匹配 + * @return 用户信息的列表 + */ + List getUserListByNickname(String nickname); + + /** * 基于手机号创建用户。 * 如果用户已经存在,则直接进行返回 @@ -47,6 +58,14 @@ public interface MemberUserService { */ MemberUserDO getUser(Long id); + /** + * 通过用户 ID 查询用户们 + * + * @param ids 用户 ID + * @return 用户对象信息数组 + */ + List getUserList(Collection ids); + /** * 修改用户昵称 * @param userId 用户id diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java index ff91b0781..58c77fa68 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/user/MemberUserServiceImpl.java +++ b/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; import javax.annotation.Resource; import javax.validation.Valid; import java.io.InputStream; +import java.util.Collection; import java.util.Date; +import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; @@ -51,6 +53,11 @@ public class MemberUserServiceImpl implements MemberUserService { return memberUserMapper.selectByMobile(mobile); } + @Override + public List getUserListByNickname(String nickname) { + return memberUserMapper.selectListByNicknameLike(nickname); + } + @Override public MemberUserDO createUserIfAbsent(String mobile, String registerIp) { // 用户已经存在 @@ -86,6 +93,11 @@ public class MemberUserServiceImpl implements MemberUserService { return memberUserMapper.selectById(id); } + @Override + public List getUserList(Collection ids) { + return memberUserMapper.selectBatchIds(ids); + } + @Override public void updateUserNickname(Long userId, String nickname) { MemberUserDO user = this.checkUserExists(userId); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleUpdateStatusReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleUpdateStatusReqVO.java index 708586b82..790accd92 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleUpdateStatusReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/permission/vo/role/RoleUpdateStatusReqVO.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -16,7 +18,7 @@ public class RoleUpdateStatusReqVO { @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举") @NotNull(message = "状态不能为空") -// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") private Integer status; } diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index fe88a0609..4c5ed6f48 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -174,6 +174,7 @@ logging: cn.iocoder.yudao.module.tool.dal.mysql: debug cn.iocoder.yudao.module.member.dal.mysql: debug cn.iocoder.yudao.module.trade.dal.mysql: debug + cn.iocoder.yudao.module.promotion.dal.mysql: debug --- #################### 微信公众号、小程序相关配置 #################### wx: diff --git a/yudao-ui-admin/src/api/mall/CouponTemplete/CouponTemplete.js b/yudao-ui-admin/src/api/mall/CouponTemplete/CouponTemplete.js deleted file mode 100644 index 639a75a1d..000000000 --- a/yudao-ui-admin/src/api/mall/CouponTemplete/CouponTemplete.js +++ /dev/null @@ -1,54 +0,0 @@ -import request from '@/utils/request' - -// 创建优惠券模板 -export function create(data) { - return request({ - url: '/coupon/template/create', - method: 'post', - data: data - }) -} - -// 更新优惠券模板 -export function update(data) { - return request({ - url: '/coupon/template/update', - method: 'put', - data: data - }) -} - -// 删除优惠券模板 -export function deleteCouponTemplete (id) { - return request({ - url: '/coupon/template/delete?id=' + id, - method: 'delete' - }) -} - -// 获得优惠券模板 -export function get(id) { - return request({ - url: '/coupon/template/get?id=' + id, - method: 'get' - }) -} - -// 获得优惠券模板分页 -export function getPage(query) { - return request({ - url: '/coupon/template/page', - method: 'get', - params: query - }) -} - -// 导出优惠券模板 Excel -export function exportExcel(query) { - return request({ - url: '/coupon/template/export-excel', - method: 'get', - params: query, - responseType: 'blob' - }) -} diff --git a/yudao-ui-admin/src/api/mall/product/sku.js b/yudao-ui-admin/src/api/mall/product/sku.js new file mode 100644 index 000000000..72b401074 --- /dev/null +++ b/yudao-ui-admin/src/api/mall/product/sku.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +// 获得商品 SKU 选项的列表 +export function getSkuOptionList() { + return request({ + url: '/product/sku/get-option-list', + method: 'get', + }) +} diff --git a/yudao-ui-admin/src/api/mall/product/spu.js b/yudao-ui-admin/src/api/mall/product/spu.js index 662f1ab61..7cce82f3b 100644 --- a/yudao-ui-admin/src/api/mall/product/spu.js +++ b/yudao-ui-admin/src/api/mall/product/spu.js @@ -1,6 +1,6 @@ import request from '@/utils/request' -// 创建商品spu +// 创建商品 SPU export function createSpu(data) { return request({ url: '/product/spu/create', @@ -9,7 +9,7 @@ export function createSpu(data) { }) } -// 更新商品spu +// 更新商品 SPU export function updateSpu(data) { return request({ url: '/product/spu/update', @@ -18,7 +18,7 @@ export function updateSpu(data) { }) } -// 删除商品spu +// 删除商品 SPU export function deleteSpu(id) { return request({ url: '/product/spu/delete?id=' + id, @@ -34,7 +34,7 @@ export function getSpu(id) { }) } -// 获得商品spu详情 +// 获得商品 SPU 详情 export function getSpuDetail(id) { return request({ url: '/product/spu/get/detail?id=' + id, @@ -42,7 +42,7 @@ export function getSpuDetail(id) { }) } -// 获得商品spu分页 +// 获得商品 SPU 分页 export function getSpuPage(query) { return request({ url: '/product/spu/page', @@ -50,3 +50,11 @@ export function getSpuPage(query) { params: query }) } + +// 获得商品 SPU 精简列表 +export function getSpuSimpleList() { + return request({ + url: '/product/spu/get-simple-list', + method: 'get', + }) +} diff --git a/yudao-ui-admin/src/api/mall/promotion/coupon.js b/yudao-ui-admin/src/api/mall/promotion/coupon.js new file mode 100755 index 000000000..d5a113b81 --- /dev/null +++ b/yudao-ui-admin/src/api/mall/promotion/coupon.js @@ -0,0 +1,18 @@ +import request from '@/utils/request' + +// 删除优惠劵 +export function deleteCoupon(id) { + return request({ + url: '/promotion/coupon/delete?id=' + id, + method: 'delete' + }) +} + +// 获得优惠劵分页 +export function getCouponPage(query) { + return request({ + url: '/promotion/coupon/page', + method: 'get', + params: query + }) +} diff --git a/yudao-ui-admin/src/api/promotion/couponTemplate.js b/yudao-ui-admin/src/api/mall/promotion/couponTemplate.js similarity index 82% rename from yudao-ui-admin/src/api/promotion/couponTemplate.js rename to yudao-ui-admin/src/api/mall/promotion/couponTemplate.js index 67d821cf0..29f81a19c 100755 --- a/yudao-ui-admin/src/api/promotion/couponTemplate.js +++ b/yudao-ui-admin/src/api/mall/promotion/couponTemplate.js @@ -18,6 +18,19 @@ export function updateCouponTemplate(data) { }) } +// 更新优惠劵模板的状态 +export function updateCouponTemplateStatus(id, status) { + const data = { + id, + status + } + return request({ + url: '/promotion/coupon-template/update-status', + method: 'put', + data: data + }) +} + // 删除优惠劵模板 export function deleteCouponTemplate(id) { return request({ diff --git a/yudao-ui-admin/src/api/mall/promotion/discountActivity.js b/yudao-ui-admin/src/api/mall/promotion/discountActivity.js new file mode 100755 index 000000000..fd32597e3 --- /dev/null +++ b/yudao-ui-admin/src/api/mall/promotion/discountActivity.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 创建限时折扣活动 +export function createDiscountActivity(data) { + return request({ + url: '/promotion/discount-activity/create', + method: 'post', + data: data + }) +} + +// 更新限时折扣活动 +export function updateDiscountActivity(data) { + return request({ + url: '/promotion/discount-activity/update', + method: 'put', + data: data + }) +} + +// 关闭限时折扣活动 +export function closeDiscountActivity(id) { + return request({ + url: '/promotion/discount-activity/close?id=' + id, + method: 'put' + }) +} + +// 删除限时折扣活动 +export function deleteDiscountActivity(id) { + return request({ + url: '/promotion/discount-activity/delete?id=' + id, + method: 'delete' + }) +} + +// 获得限时折扣活动 +export function getDiscountActivity(id) { + return request({ + url: '/promotion/discount-activity/get?id=' + id, + method: 'get' + }) +} + +// 获得限时折扣活动分页 +export function getDiscountActivityPage(query) { + return request({ + url: '/promotion/discount-activity/page', + method: 'get', + params: query + }) +} diff --git a/yudao-ui-admin/src/api/mall/promotion/rewardActivity.js b/yudao-ui-admin/src/api/mall/promotion/rewardActivity.js new file mode 100755 index 000000000..b792f903b --- /dev/null +++ b/yudao-ui-admin/src/api/mall/promotion/rewardActivity.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 创建满减送活动 +export function createRewardActivity(data) { + return request({ + url: '/promotion/reward-activity/create', + method: 'post', + data: data + }) +} + +// 更新满减送活动 +export function updateRewardActivity(data) { + return request({ + url: '/promotion/reward-activity/update', + method: 'put', + data: data + }) +} + +// 关闭满减送活动 +export function closeRewardActivity(id) { + return request({ + url: '/promotion/reward-activity/close?id=' + id, + method: 'put' + }) +} + +// 删除满减送活动 +export function deleteRewardActivity(id) { + return request({ + url: '/promotion/reward-activity/delete?id=' + id, + method: 'delete' + }) +} + +// 获得满减送活动 +export function getRewardActivity(id) { + return request({ + url: '/promotion/reward-activity/get?id=' + id, + method: 'get' + }) +} + +// 获得满减送活动分页 +export function getRewardActivityPage(query) { + return request({ + url: '/promotion/reward-activity/page', + method: 'get', + params: query + }) +} diff --git a/yudao-ui-admin/src/utils/constants.js b/yudao-ui-admin/src/utils/constants.js index 1480c6f26..3efb0e3c0 100644 --- a/yudao-ui-admin/src/utils/constants.js +++ b/yudao-ui-admin/src/utils/constants.js @@ -278,3 +278,39 @@ export const PromotionProductScopeEnum = { name: '指定商品参与' } } + +/** + * 营销的条件类型枚举 + */ +export const PromotionConditionTypeEnum = { + PRICE: { + type: 10, + name: '满 N 元' + }, + COUNT: { + type: 20, + name: '满 N 件' + } +} + +/** + * 促销活动的状态枚举 + */ +export const PromotionActivityStatusEnum = { + WAIT: { + type: 10, + name: '未开始' + }, + RUN: { + type: 20, + name: '进行中' + }, + END: { + type: 30, + name: '已结束' + }, + CLOSE: { + type: 40, + name: '已关闭' + } +} diff --git a/yudao-ui-admin/src/utils/dict.js b/yudao-ui-admin/src/utils/dict.js index 786e41cfb..f669c4316 100644 --- a/yudao-ui-admin/src/utils/dict.js +++ b/yudao-ui-admin/src/utils/dict.js @@ -63,7 +63,11 @@ export const DICT_TYPE = { // ========== MALL - PROMOTION 模块 ========== PROMOTION_DISCOUNT_TYPE: 'promotion_discount_type', // 优惠类型 PROMOTION_PRODUCT_SCOPE: 'promotion_product_scope', // 营销的商品范围 - COUPON_TEMPLATE_VALIDITY_TYPE: 'coupon_template_validity_type', // 优惠劵模板的有限期类型 + PROMOTION_COUPON_TEMPLATE_VALIDITY_TYPE: 'promotion_coupon_template_validity_type', // 优惠劵模板的有限期类型 + PROMOTION_COUPON_STATUS: 'promotion_coupon_status', // 优惠劵的状态 + PROMOTION_COUPON_TAKE_TYPE: 'promotion_coupon_take_type', // 优惠劵的领取方式 + PROMOTION_ACTIVITY_STATUS: 'promotion_activity_status', // 优惠活动的状态 + PROMOTION_CONDITION_TYPE: 'promotion_condition_type', // 营销的条件类型枚举 } /** diff --git a/yudao-ui-admin/src/views/mall/CouponTemplete/index.vue b/yudao-ui-admin/src/views/mall/CouponTemplete/index.vue deleted file mode 100644 index 945bb03ea..000000000 --- a/yudao-ui-admin/src/views/mall/CouponTemplete/index.vue +++ /dev/null @@ -1,460 +0,0 @@ - - - diff --git a/yudao-ui-admin/src/views/mall/promotion/coupon/index.vue b/yudao-ui-admin/src/views/mall/promotion/coupon/index.vue new file mode 100755 index 000000000..9049900c6 --- /dev/null +++ b/yudao-ui-admin/src/views/mall/promotion/coupon/index.vue @@ -0,0 +1,162 @@ + + + diff --git a/yudao-ui-admin/src/views/promotion/couponTemplate/index.vue b/yudao-ui-admin/src/views/mall/promotion/couponTemplate/index.vue similarity index 79% rename from yudao-ui-admin/src/views/promotion/couponTemplate/index.vue rename to yudao-ui-admin/src/views/mall/promotion/couponTemplate/index.vue index 87e0f2d0a..3e77bb008 100755 --- a/yudao-ui-admin/src/views/promotion/couponTemplate/index.vue +++ b/yudao-ui-admin/src/views/mall/promotion/couponTemplate/index.vue @@ -33,6 +33,9 @@ 新增 + 会员优惠劵 @@ -52,7 +55,7 @@ @@ -108,7 +111,7 @@ - @@ -117,13 +120,13 @@ - {{dict.label}} - + - + + + {{ item.name }} + ¥{{ (item.minPrice / 100.0).toFixed(2) }} + +