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

This commit is contained in:
LAPTOP-CNV4CMCJ\cheng 2022-11-08 00:16:15 +08:00
commit fb45f22533
112 changed files with 4145 additions and 1074 deletions

View File

@ -1,14 +1,57 @@
package cn.iocoder.yudao.module.product.controller.admin.sku; 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.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated; 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.RequestMapping;
import org.springframework.web.bind.annotation.RestController; 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") @Api(tags = "管理后台 - 商品 sku")
@RestController @RestController
@RequestMapping("/product/sku") @RequestMapping("/product/sku")
@Validated @Validated
public class ProductSkuController { 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<List<ProductSkuOptionRespVO>> getSkuOptionList() {
// 获得 SKU 列表
List<ProductSkuDO> skus = productSkuService.getSkuList();
if (CollUtil.isEmpty(skus)) {
return success(Collections.emptyList());
}
// 获得对应的 SPU 映射
Map<Long, ProductSpuDO> spuMap = productSpuService.getSpuMap(convertSet(skus, ProductSkuDO::getSpuId));
// 转换为返回结果
List<ProductSkuOptionRespVO> skuVOs = ProductSkuConvert.INSTANCE.convertList05(skus);
skuVOs.forEach(sku -> MapUtils.findAndThen(spuMap, sku.getSpuId(),
spu -> sku.setSpuId(spu.getId()).setSpuName(spu.getName())));
return success(skuVOs);
}
} }

View File

@ -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;
}

View File

@ -9,7 +9,7 @@ import lombok.ToString;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ApiModel("管理后台 - 商品sku Response VO") @ApiModel("管理后台 - 商品 SKU Response VO")
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true) @ToString(callSuper = true)

View File

@ -53,6 +53,7 @@ public class ProductSpuController {
return success(true); return success(true);
} }
// TODO 芋艿修改接口
@GetMapping("/get/detail") @GetMapping("/get/detail")
@ApiOperation("获得商品 SPU") @ApiOperation("获得商品 SPU")
@ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
@ -79,6 +80,14 @@ public class ProductSpuController {
return success(ProductSpuConvert.INSTANCE.convertList(list)); return success(ProductSpuConvert.INSTANCE.convertList(list));
} }
@GetMapping("/get-simple-list")
@ApiOperation("获得商品 SPU 精简列表")
@PreAuthorize("@ss.hasPermission('product:spu:query')")
public CommonResult<List<ProductSpuSimpleRespVO>> getSpuSimpleList() {
List<ProductSpuDO> list = spuService.getSpuList();
return success(ProductSpuConvert.INSTANCE.convertList02(list));
}
@GetMapping("/page") @GetMapping("/page")
@ApiOperation("获得商品 SPU 分页") @ApiOperation("获得商品 SPU 分页")
@PreAuthorize("@ss.hasPermission('product:spu:query')") @PreAuthorize("@ss.hasPermission('product:spu:query')")

View File

@ -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;
}

View File

@ -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.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.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.sku.vo.ProductSkuRespVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuDetailRespVO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
@ -11,7 +12,7 @@ import org.mapstruct.factory.Mappers;
import java.util.List; import java.util.List;
/** /**
* 商品sku Convert * 商品 SKU Convert
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@ -36,4 +37,6 @@ public interface ProductSkuConvert {
List<ProductSkuRespDTO> convertList04(List<ProductSkuDO> list); List<ProductSkuRespDTO> convertList04(List<ProductSkuDO> list);
List<ProductSkuOptionRespVO> convertList05(List<ProductSkuDO> skus);
} }

View File

@ -37,4 +37,6 @@ public interface ProductSpuConvert {
List<SpuInfoRespDTO> convertList2(List<ProductSpuDO> list); List<SpuInfoRespDTO> convertList2(List<ProductSpuDO> list);
List<ProductSpuSimpleRespVO> convertList02(List<ProductSpuDO> list);
} }

View File

@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO {
* 商品属性 * 商品属性
*/ */
@Data @Data
@NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class Property { 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 活动限购数量显示
} }

View File

@ -14,22 +14,29 @@ import java.util.List;
public interface ProductSkuService { public interface ProductSkuService {
/** /**
* 删除商品sku * 删除商品 SKU
* *
* @param id 编号 * @param id 编号
*/ */
void deleteSku(Long id); void deleteSku(Long id);
/** /**
* 获得商品sku * 获得商品 SKU 信息
* *
* @param id 编号 * @param id 编号
* @return 商品sku * @return 商品 SKU 信息
*/ */
ProductSkuDO getSku(Long id); ProductSkuDO getSku(Long id);
/** /**
* 获得商品sku列表 * 获得商品 SKU 列表
*
* @return 商品sku列表
*/
List<ProductSkuDO> getSkuList();
/**
* 获得商品 SKU 列表
* *
* @param ids 编号 * @param ids 编号
* @return 商品sku列表 * @return 商品sku列表

View File

@ -61,6 +61,11 @@ public class ProductSkuServiceImpl implements ProductSkuService {
return productSkuMapper.selectById(id); return productSkuMapper.selectById(id);
} }
@Override
public List<ProductSkuDO> getSkuList() {
return productSkuMapper.selectList();
}
@Override @Override
public List<ProductSkuDO> getSkuList(Collection<Long> ids) { public List<ProductSkuDO> getSkuList(Collection<Long> ids) {
return productSkuMapper.selectBatchIds(ids); return productSkuMapper.selectBatchIds(ids);

View File

@ -9,6 +9,9 @@ import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/** /**
* 商品 SPU Service 接口 * 商品 SPU Service 接口
@ -63,6 +66,23 @@ public interface ProductSpuService {
*/ */
List<ProductSpuDO> getSpuList(Collection<Long> ids); List<ProductSpuDO> getSpuList(Collection<Long> ids);
/**
* 获得商品 SPU 映射
*
* @param ids 编号数组
* @return 商品 SPU 映射
*/
default Map<Long, ProductSpuDO> getSpuMap(Collection<Long> ids) {
return convertMap(getSpuList(ids), ProductSpuDO::getId);
}
/**
* 获得所有商品 SPU 列表
*
* @return 商品 SPU 列表
*/
List<ProductSpuDO> getSpuList();
/** /**
* 获得商品 SPU 分页 * 获得商品 SPU 分页
* *

View File

@ -176,6 +176,11 @@ public class ProductSpuServiceImpl implements ProductSpuService {
return productSpuMapper.selectBatchIds(ids); return productSpuMapper.selectBatchIds(ids);
} }
@Override
public List<ProductSpuDO> getSpuList() {
return productSpuMapper.selectList();
}
@Override @Override
public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) { public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
// 库存告警的 SPU 编号的集合 // 库存告警的 SPU 编号的集合

View File

@ -48,9 +48,17 @@ public class PriceCalculateRespDTO {
* 商品原价单位 * 商品原价单位
* *
* 基于 {@link OrderItem#getOriginalPrice()} 求和 * 基于 {@link OrderItem#getOriginalPrice()} 求和
*
* 对应 taobao trade.total_fee 字段 * 对应 taobao trade.total_fee 字段
*/ */
private Integer originalPrice; private Integer originalPrice;
/**
* 订单原价单位
*
* 基于 {@link OrderItem#getPayPrice()} 求和
* {@link #originalPrice} 的差异去除商品级优惠
*/
private Integer orderPrice;
/** /**
* 订单优惠单位 * 订单优惠单位
* *
@ -82,6 +90,7 @@ public class PriceCalculateRespDTO {
* - {@link #couponPrice} * - {@link #couponPrice}
* - {@link #pointPrice} * - {@link #pointPrice}
* + {@link #deliveryPrice} * + {@link #deliveryPrice}
* - {@link #discountPrice}
*/ */
private Integer payPrice; private Integer payPrice;
/** /**

View File

@ -3,14 +3,19 @@ package cn.iocoder.yudao.module.promotion.enums;
import cn.iocoder.yudao.framework.common.exception.ErrorCode; import cn.iocoder.yudao.framework.common.exception.ErrorCode;
/** /**
* market 错误码枚举类 * promotion 错误码枚举类
* <p> *
* market 系统使用 1-003-000-000 * market 系统使用 1-003-000-000
*/ */
public interface ErrorCodeConstants { public interface ErrorCodeConstants {
// ========== 促销活动相关 1003001000 ============ TODO 芋艿看看是不是要删除掉 // ========== 促销活动相关 1003001000 ============
ErrorCode ACTIVITY_NOT_EXISTS = new ErrorCode(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 ============ // ========== Banner 相关 1003002000 ============
ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1003002000, "Banner 不存在"); 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_NOT_EXISTS = new ErrorCode(1003004000, "优惠劵模板不存在");
ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1003004001, "发放数量不能小于已领取数量({})"); 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");
} }

View File

@ -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;
}
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.promotion.enums.coupon; package cn.iocoder.yudao.module.promotion.enums.coupon;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable; import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays; import java.util.Arrays;
@ -9,6 +11,8 @@ import java.util.Arrays;
* *
* @author 芋道源码 * @author 芋道源码
*/ */
@AllArgsConstructor
@Getter
public enum CouponTakeTypeEnum implements IntArrayValuable { public enum CouponTakeTypeEnum implements IntArrayValuable {
BY_USER(1, "直接领取"), // 用户可在首页每日领劵直接领取 BY_USER(1, "直接领取"), // 用户可在首页每日领劵直接领取
@ -26,19 +30,6 @@ public enum CouponTakeTypeEnum implements IntArrayValuable {
*/ */
private final String name; 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 @Override
public int[] array() { public int[] array() {
return ARRAYS; return ARRAYS;

View File

@ -29,6 +29,11 @@
<artifactId>yudao-module-product-api</artifactId> <artifactId>yudao-module-product-api</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-member-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- 业务组件 --> <!-- 业务组件 -->
<dependency> <dependency>

View File

@ -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<CouponRespVO> 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<Boolean> deleteCoupon(@RequestParam("id") Long id) {
couponService.deleteCoupon(id);
return success(true);
}
@GetMapping("/page")
@ApiOperation("获得优惠劵分页")
@PreAuthorize("@ss.hasPermission('promotion:coupon:query')")
public CommonResult<PageResult<CouponPageItemRespVO>> getCouponPage(@Valid CouponPageReqVO pageVO) {
PageResult<CouponDO> pageResult = couponService.getCouponPage(pageVO);
PageResult<CouponPageItemRespVO> pageResulVO = CouponConvert.INSTANCE.convertPage(pageResult);
if (CollUtil.isEmpty(pageResulVO.getList())) {
return success(pageResulVO);
}
// 读取用户信息进行拼接
Set<Long> userIds = convertSet(pageResult.getList(), CouponDO::getUserId);
Map<Long, UserRespDTO> userMap = memberUserApi.getUserMap(userIds);
pageResulVO.getList().forEach(itemRespVO -> MapUtils.findAndThen(userMap, itemRespVO.getUserId(),
userRespDTO -> itemRespVO.setNickname(userRespDTO.getNickname())));
return success(pageResulVO);
}
}

View File

@ -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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.template.*;
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.convert.coupon.CouponTemplateConvert; 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.dataobject.coupon.CouponTemplateDO;
import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService; import cn.iocoder.yudao.module.promotion.service.coupon.CouponTemplateService;
@ -45,6 +42,14 @@ public class CouponTemplateController {
return success(true); return success(true);
} }
@PutMapping("/update-status")
@ApiOperation("更新优惠劵模板状态")
@PreAuthorize("@ss.hasPermission('promotion:coupon-template:update')")
public CommonResult<Boolean> updateCouponTemplateStatus(@Valid @RequestBody CouponTemplateUpdateStatusReqVO reqVO) {
couponTemplateService.updateCouponTemplateStatus(reqVO.getId(), reqVO.getStatus());
return success(true);
}
@DeleteMapping("/delete") @DeleteMapping("/delete")
@ApiOperation("删除优惠劵模板") @ApiOperation("删除优惠劵模板")
@ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)

View File

@ -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<Long> 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 ==========
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil; 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.PromotionDiscountTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum; import cn.iocoder.yudao.module.promotion.enums.coupon.CouponTemplateValidityTypeEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -19,6 +20,7 @@ import java.util.List;
import java.util.Objects; 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.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.TIME_ZONE_DEFAULT;
/** /**
* 优惠劵模板 Base VO提供给添加修改详细的子 VO 使用 * 优惠劵模板 Base VO提供给添加修改详细的子 VO 使用
@ -62,10 +64,12 @@ public class CouponTemplateBaseVO {
@ApiModelProperty(value = "固定日期 - 生效开始时间") @ApiModelProperty(value = "固定日期 - 生效开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @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; private Date validStartTime;
@ApiModelProperty(value = "固定日期 - 生效结束时间") @ApiModelProperty(value = "固定日期 - 生效结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @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; private Date validEndTime;
@ApiModelProperty(value = "领取日期 - 开始天数") @ApiModelProperty(value = "领取日期 - 开始天数")
@ -82,15 +86,14 @@ public class CouponTemplateBaseVO {
private Integer discountType; private Integer discountType;
@ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说80% 为 80") @ApiModelProperty(value = "折扣百分比", example = "80", notes = "例如说80% 为 80")
@Min(value = 1)
private Integer discountPercent; private Integer discountPercent;
@ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分") @ApiModelProperty(value = "优惠金额", example = "10", notes = "单位:分")
@Min(value = 1) @Min(value = 0, message = "优惠金额需要大于等于 0")
private Integer discountPrice; private Integer discountPrice;
@ApiModelProperty(value = "折扣上限", example = "100", notes = "单位:分,仅在 discountType 为 PERCENT 使用") @ApiModelProperty(value = "折扣上限", example = "100", notes = "单位:分,仅在 discountType 为 PERCENT 使用")
private Integer discountPriceLimit; private Integer discountLimitPrice;
@AssertTrue(message = "商品 SPU 编号的数组不能为空") @AssertTrue(message = "商品 SPU 编号的数组不能为空")
@JsonIgnore @JsonIgnore
@ -127,11 +130,11 @@ public class CouponTemplateBaseVO {
|| fixedEndTerm != null; || fixedEndTerm != null;
} }
@AssertTrue(message = "折扣百分比不能为空") @AssertTrue(message = "折扣百分比需要大于等于 1小于等于 99")
@JsonIgnore @JsonIgnore
public boolean isDiscountPercentValid() { public boolean isDiscountPercentValid() {
return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
|| discountPercent != null; || (discountPercent != null && discountPercent >= 1 && discountPercent<= 99);
} }
@AssertTrue(message = "优惠金额不能为空") @AssertTrue(message = "优惠金额不能为空")
@ -143,9 +146,9 @@ public class CouponTemplateBaseVO {
@AssertTrue(message = "折扣上限不能为空") @AssertTrue(message = "折扣上限不能为空")
@JsonIgnore @JsonIgnore
public boolean isDiscountPriceLimit() { public boolean isDiscountLimitPriceValid() {
return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType()) return ObjectUtil.notEqual(discountType, PromotionDiscountTypeEnum.PERCENT.getType())
|| discountPriceLimit != null; || discountLimitPrice != null;
} }
} }

View File

@ -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.ApiModel;
import lombok.Data; import lombok.Data;

View File

@ -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.pojo.PageParam;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;

View File

@ -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.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.validation.InEnum; import cn.iocoder.yudao.framework.common.validation.InEnum;

View File

@ -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.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;

View File

@ -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;
}

View File

@ -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<Long> createDiscountActivity(@Valid @RequestBody DiscountActivityCreateReqVO createReqVO) {
return success(discountActivityService.createDiscountActivity(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新限时折扣活动")
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:update')")
public CommonResult<Boolean> 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<Boolean> 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<Boolean> 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<DiscountActivityDetailRespVO> getDiscountActivity(@RequestParam("id") Long id) {
DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id);
if (discountActivity == null) {
return success(null);
}
// 拼接结果
List<DiscountProductDO> discountProducts = discountActivityService.getDiscountProductsByActivityId(id);
return success(DiscountActivityConvert.INSTANCE.convert(discountActivity, discountProducts));
}
@GetMapping("/page")
@ApiOperation("获得限时折扣活动分页")
@PreAuthorize("@ss.hasPermission('promotion:discount-activity:query')")
public CommonResult<PageResult<DiscountActivityRespVO>> getDiscountActivityPage(@Valid DiscountActivityPageReqVO pageVO) {
PageResult<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(pageVO);
return success(DiscountActivityConvert.INSTANCE.convertPage(pageResult));
}
}

View File

@ -1,4 +0,0 @@
/**
* TODO 占位
*/
package cn.iocoder.yudao.module.promotion.controller.admin.discount;

View File

@ -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;
}
}
}

View File

@ -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<Product> products;
}

View File

@ -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<Product> products;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<DiscountActivityCreateReqVO.Product> products;
}

View File

@ -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<Long> createRewardActivity(@Valid @RequestBody RewardActivityCreateReqVO createReqVO) {
return success(rewardActivityService.createRewardActivity(createReqVO));
}
@PutMapping("/update")
@ApiOperation("更新满减送活动")
@PreAuthorize("@ss.hasPermission('promotion:reward-activity:update')")
public CommonResult<Boolean> 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<Boolean> 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<Boolean> 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<RewardActivityRespVO> 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<PageResult<RewardActivityRespVO>> getRewardActivityPage(@Valid RewardActivityPageReqVO pageVO) {
PageResult<RewardActivityDO> pageResult = rewardActivityService.getRewardActivityPage(pageVO);
return success(RewardActivityConvert.INSTANCE.convertPage(pageResult));
}
}

View File

@ -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<Long> productSpuIds;
/**
* 优惠规则的数组
*/
@Valid // 校验下子对象
private List<Rule> 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<Long> couponIds;
@ApiModelProperty(value = "赠送的优惠卷数量的数组", example = "1,2,3")
private List<Integer> couponCounts;
@AssertTrue(message = "优惠劵和数量必须一一对应")
@JsonIgnore
public boolean isCouponCountsValid() {
return CollUtil.size(couponCounts) == CollUtil.size(couponCounts);
}
}
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<CouponPageItemRespVO> convertPage(PageResult<CouponDO> page);
}

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.promotion.convert.coupon; package cn.iocoder.yudao.module.promotion.convert.coupon;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.template.CouponTemplateCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 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.dataobject.coupon.CouponTemplateDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;

View File

@ -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<DiscountActivityRespVO> convertList(List<DiscountActivityDO> list);
PageResult<DiscountActivityRespVO> convertPage(PageResult<DiscountActivityDO> page);
DiscountProductDetailBO convert(DiscountProductDO product);
default List<DiscountProductDetailBO> convertList(List<DiscountProductDO> products, Map<Long, DiscountActivityDO> 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<DiscountProductDO> 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;
}
}

View File

@ -1,4 +0,0 @@
/**
* TODO 占位
*/
package cn.iocoder.yudao.module.promotion.convert.discount;

View File

@ -36,7 +36,8 @@ public interface PriceConvert {
orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice()); orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice());
priceCalculate.getOrder().getItems().add(orderItem); priceCalculate.getOrder().getItems().add(orderItem);
// 补充价格信息到 Order // 补充价格信息到 Order
order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice()).setPayPrice(order.getOriginalPrice()); order.setOriginalPrice(order.getOriginalPrice() + orderItem.getOriginalPrice())
.setOrderPrice(order.getOriginalPrice()).setPayPrice(order.getOriginalPrice());
}); });
return priceCalculate; return priceCalculate;
} }

View File

@ -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<RewardActivityRespVO> convertPage(PageResult<RewardActivityDO> page);
}

View File

@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.coupon; 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.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.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.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -14,9 +17,11 @@ import java.util.List;
/** /**
* 优惠劵 DO * 优惠劵 DO
*
* @author 芋道源码
*/ */
@TableName(value = "promotion_coupon", autoResultMap = true) @TableName(value = "promotion_coupon", autoResultMap = true)
@KeySequence("promotion_coupo_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写 @KeySequence("promotion_coupon_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class CouponDO extends BaseDO { public class CouponDO extends BaseDO {
@ -35,21 +40,13 @@ public class CouponDO extends BaseDO {
/** /**
* 优惠劵名 * 优惠劵名
* *
* 冗余自 {@link CouponTemplateDO} title * 冗余 {@link CouponTemplateDO#getName()}
*
* TODO 芋艿暂时不考虑冗余的更新
*/ */
private String title; private String name;
// /**
// * 核销码
// */
// private String verifyCode;
/** /**
* 优惠码状态 * 优惠码状态
* *
* 1-未使用 * 枚举 {@link CouponStatusEnum}
* 2-已使用
* 3-已失效
*/ */
private Integer status; private Integer status;
@ -58,13 +55,14 @@ public class CouponDO extends BaseDO {
// ========== 领取情况 BEGIN ========== // ========== 领取情况 BEGIN ==========
/** /**
* 用户编号 * 用户编号
*
* 关联 MemberUserDO id 字段
*/ */
private Integer userId; private Long userId;
/** /**
* 领取类型 * 领取类型
* *
* 1 - 用户主动领取 * 枚举 {@link CouponTakeTypeEnum}
* 2 - 后台自动发放
*/ */
private Integer takeType; private Integer takeType;
// ========== 领取情况 END ========== // ========== 领取情况 END ==========
@ -72,8 +70,10 @@ public class CouponDO extends BaseDO {
// ========== 使用规则 BEGIN ========== // ========== 使用规则 BEGIN ==========
/** /**
* 是否设置满多少金额可用单位 * 是否设置满多少金额可用单位
*
* 冗余 {@link CouponTemplateDO#getUsePrice()}
*/ */
private Integer priceAvailable; private Integer usePrice;
/** /**
* 生效开始时间 * 生效开始时间
*/ */
@ -90,50 +90,49 @@ public class CouponDO extends BaseDO {
private Integer productScope; private Integer productScope;
/** /**
* 商品 SPU 编号的数组 * 商品 SPU 编号的数组
*
* 冗余 {@link CouponTemplateDO#getProductSpuIds()}
*/ */
@TableField(typeHandler = JacksonTypeHandler.class) @TableField(typeHandler = LongListTypeHandler.class)
private List<Long> spuIds; private List<Long> productSpuIds;
// ========== 使用规则 END ========== // ========== 使用规则 END ==========
// ========== 使用效果 BEGIN ========== // ========== 使用效果 BEGIN ==========
/** /**
* 优惠类型 * 折扣类型
* *
* 1-代金卷 * 冗余 {@link CouponTemplateDO#getDiscountType()}
* 2-折扣卷
*/ */
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 ========== // ========== 使用效果 END ==========
// ========== 使用情况 BEGIN ========== // ========== 使用情况 BEGIN ==========
// /** /**
// * 使用订单号 * 使用订单号
// */ */
// private Integer usedOrderId; // TODO 芋艿暂时不考虑这个字段 private Long useOrderId;
// /**
// * 订单中优惠面值单位
// */
// private Integer usedPrice; // TODO 芋艿暂时不考虑这个字段
/** /**
* 使用时间 * 使用时间
*/ */
private Date usedTime; private Date useTime;
// TODO 芋艿后续要加优惠劵的使用日志因为下单后可能会取消
// ========== 使用情况 END ========== // ========== 使用情况 END ==========

View File

@ -21,6 +21,8 @@ import java.util.List;
* 优惠劵模板 DO * 优惠劵模板 DO
* *
* 当用户领取时会生成 {@link CouponDO} 优惠劵 * 当用户领取时会生成 {@link CouponDO} 优惠劵
*
* @author 芋道源码
*/ */
@TableName(value = "promotion_coupon_template", autoResultMap = true) @TableName(value = "promotion_coupon_template", autoResultMap = true)
@KeySequence("promotion_coupon_template_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写 @KeySequence("promotion_coupon_template_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写

View File

@ -1,14 +1,13 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.discount; package cn.iocoder.yudao.module.promotion.dal.dataobject.discount;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.util.Date;
/** /**
* 限时折扣商品 DO * 限时折扣商品 DO
* *
@ -31,12 +30,6 @@ public class DiscountProductDO extends BaseDO {
* 关联 {@link DiscountActivityDO#getId()} * 关联 {@link DiscountActivityDO#getId()}
*/ */
private Long activityId; private Long activityId;
/**
* 限时折扣活动的名字
*
* 冗余 {@link DiscountActivityDO#getName()}
*/
private String activityName;
/** /**
* 商品 SPU 编号 * 商品 SPU 编号
* *
@ -49,23 +42,24 @@ public class DiscountProductDO extends BaseDO {
* 关联 ProductSkuDO id 编号 * 关联 ProductSkuDO id 编号
*/ */
private Long skuId; 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;
} }

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.reward; 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.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.PromotionActivityStatusEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; 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.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; 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.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -68,19 +71,19 @@ public class RewardActivityDO extends BaseDO {
/** /**
* 商品 SPU 编号的数组 * 商品 SPU 编号的数组
*/ */
@TableField(typeHandler = JacksonTypeHandler.class) @TableField(typeHandler = LongListTypeHandler.class)
private List<Long> productSpuIds; private List<Long> productSpuIds;
/** /**
* 优惠规则的数组 * 优惠规则的数组
*/ */
@TableField(typeHandler = JacksonTypeHandler.class) @TableField(typeHandler = RuleTypeHandler.class)
private List<Rule> rules; private List<Rule> rules;
/** /**
* 优惠规则 * 优惠规则
*/ */
@Data @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<List<Rule>> {
@Override
protected List<Rule> parse(String json) {
return JsonUtils.parseArray(json, Rule.class);
}
@Override
protected String toJson(List<Rule> obj) {
return JsonUtils.toJsonString(obj);
}
}
} }

View File

@ -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<CouponDO> {
default PageResult<CouponDO> selectPage(CouponPageReqVO reqVO, Collection<Long> userIds) {
return selectPage(reqVO, new LambdaQueryWrapperX<CouponDO>()
.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<Integer> whereStatuses) {
return update(null, new LambdaUpdateWrapper<CouponDO>()
.eq(CouponDO::getId, id).in(CouponDO::getStatus, whereStatuses)
.set(CouponDO::getDeleted, 1));
}
}

View File

@ -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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.controller.admin.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 cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/** /**
* 优惠劵模板 Mapper * 优惠劵模板 Mapper
@ -24,4 +25,6 @@ public interface CouponTemplateMapper extends BaseMapperX<CouponTemplateDO> {
.orderByDesc(CouponTemplateDO::getId)); .orderByDesc(CouponTemplateDO::getId));
} }
void updateTakeCount(@Param("id") Long id, @Param("incrCount") Integer incrCount);
} }

View File

@ -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<DiscountActivityDO> {
default PageResult<DiscountActivityDO> selectPage(DiscountActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<DiscountActivityDO>()
.likeIfPresent(DiscountActivityDO::getName, reqVO.getName())
.eqIfPresent(DiscountActivityDO::getStatus, reqVO.getStatus())
.betweenIfPresent(DiscountActivityDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DiscountActivityDO::getId));
}
}

View File

@ -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<DiscountProductDO> {
default List<DiscountProductDO> selectListBySkuId(Collection<Long> skuIds) {
return selectList(DiscountProductDO::getSkuId, skuIds);
}
default List<DiscountProductDO> selectListByActivityId(Long activityId) {
return selectList(DiscountProductDO::getActivityId, activityId);
}
}

View File

@ -1,4 +0,0 @@
/**
* TODO 占位
*/
package cn.iocoder.yudao.module.promotion.dal.mysql.discount;

View File

@ -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<RewardActivityDO> {
default PageResult<RewardActivityDO> selectPage(RewardActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<RewardActivityDO>()
.likeIfPresent(RewardActivityDO::getName, reqVO.getName())
.eqIfPresent(RewardActivityDO::getStatus, reqVO.getStatus())
.orderByDesc(RewardActivityDO::getId));
}
default List<RewardActivityDO> selectListByStatus(Collection<Integer> statuses) {
return selectList(RewardActivityDO::getStatus, statuses);
}
default List<RewardActivityDO> selectListByProductScopeAndStatus(Integer productScope, Integer status) {
return selectList(new LambdaQueryWrapperX<RewardActivityDO>()
.eq(RewardActivityDO::getProductScope, productScope)
.eq(RewardActivityDO::getStatus, status));
}
}

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.promotion.service.coupon; 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; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
/** /**
@ -21,4 +23,19 @@ public interface CouponService {
*/ */
CouponDO validCoupon(Long id, Long userId); CouponDO validCoupon(Long id, Long userId);
/**
* 获得优惠劵分页
*
* @param pageReqVO 分页查询
* @return 优惠劵分页
*/
PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO);
/**
* 回收优惠劵
*
* @param id 优惠劵编号
*/
void deleteCoupon(Long id);
} }

View File

@ -1,9 +1,27 @@
package cn.iocoder.yudao.module.promotion.service.coupon; 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.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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; 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 实现类 * 优惠劵 Service 实现类
* *
@ -13,9 +31,56 @@ import org.springframework.validation.annotation.Validated;
@Validated @Validated
public class CouponServiceImpl implements CouponService { public class CouponServiceImpl implements CouponService {
@Resource
private CouponTemplateService couponTemplateService;
@Resource
private CouponMapper couponMapper;
@Resource
private MemberUserApi memberUserApi;
// TODO 芋艿待实现 // TODO 芋艿待实现
@Override @Override
public CouponDO validCoupon(Long id, Long userId) { public CouponDO validCoupon(Long id, Long userId) {
return null; return null;
} }
@Override
public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) {
// 获得用户编号
Set<Long> 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);
}
}
} }

View File

@ -1,9 +1,9 @@
package cn.iocoder.yudao.module.promotion.service.coupon; package cn.iocoder.yudao.module.promotion.service.coupon;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.template.CouponTemplateCreateReqVO;
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.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 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.dataobject.coupon.CouponTemplateDO;
import javax.validation.Valid; import javax.validation.Valid;
@ -30,6 +30,14 @@ public interface CouponTemplateService {
*/ */
void updateCouponTemplate(@Valid CouponTemplateUpdateReqVO updateReqVO); void updateCouponTemplate(@Valid CouponTemplateUpdateReqVO updateReqVO);
/**
* 更新优惠劵模板的状态
*
* @param id 编号
* @param status 状态
*/
void updateCouponTemplateStatus(Long id, Integer status);
/** /**
* 删除优惠劵模板 * 删除优惠劵模板
* *
@ -53,4 +61,12 @@ public interface CouponTemplateService {
*/ */
PageResult<CouponTemplateDO> getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO); PageResult<CouponTemplateDO> getCouponTemplatePage(CouponTemplatePageReqVO pageReqVO);
/**
* 更新优惠劵模板的领取数量
*
* @param id 优惠劵模板编号
* @param incrCount 增加数量
*/
void updateCouponTemplateTakeCount(Long id, int incrCount);
} }

View File

@ -1,9 +1,10 @@
package cn.iocoder.yudao.module.promotion.service.coupon; 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.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.CouponTemplateCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.coupon.vo.template.CouponTemplateCreateReqVO;
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.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 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.convert.coupon.CouponTemplateConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponTemplateDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper;
@ -30,7 +31,8 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
@Override @Override
public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) { public Long createCouponTemplate(CouponTemplateCreateReqVO createReqVO) {
// 插入 // 插入
CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO); CouponTemplateDO couponTemplate = CouponTemplateConvert.INSTANCE.convert(createReqVO)
.setStatus(CommonStatusEnum.ENABLE.getStatus());
couponTemplateMapper.insert(couponTemplate); couponTemplateMapper.insert(couponTemplate);
// 返回 // 返回
return couponTemplate.getId(); return couponTemplate.getId();
@ -50,6 +52,14 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
couponTemplateMapper.updateById(updateObj); couponTemplateMapper.updateById(updateObj);
} }
@Override
public void updateCouponTemplateStatus(Long id, Integer status) {
// 校验存在
validateCouponTemplateExists(id);
// 更新
couponTemplateMapper.updateById(new CouponTemplateDO().setId(id).setStatus(status));
}
@Override @Override
public void deleteCouponTemplate(Long id) { public void deleteCouponTemplate(Long id) {
// 校验存在 // 校验存在
@ -76,4 +86,9 @@ public class CouponTemplateServiceImpl implements CouponTemplateService {
return couponTemplateMapper.selectPage(pageReqVO); return couponTemplateMapper.selectPage(pageReqVO);
} }
@Override
public void updateCouponTemplateTakeCount(Long id, int incrCount) {
couponTemplateMapper.updateTakeCount(id, incrCount);
}
} }

View File

@ -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<Long, DiscountProductDetailBO> getMatchDiscountProducts(Collection<Long> 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<DiscountActivityDO> getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO);
/**
* 获得活动编号对应对应的商品列表
*
* @param activityId 活动编号
* @return 活动的商品列表
*/
List<DiscountProductDO> getDiscountProductsByActivityId(Long activityId);
}

View File

@ -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<Long, DiscountProductDetailBO> getMatchDiscountProducts(Collection<Long> skuIds) {
List<DiscountProductDetailBO> 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<DiscountProductDO> 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<DiscountProductDO> dbDiscountProducts = discountProductMapper.selectListByActivityId(updateReqVO.getId());
// 计算要删除的记录
List<Long> deleteIds = convertList(dbDiscountProducts, DiscountProductDO::getId,
discountProductDO -> updateReqVO.getProducts().stream()
.noneMatch(product -> DiscountActivityConvert.INSTANCE.isEquals(discountProductDO, product)));
if (CollUtil.isNotEmpty(deleteIds)) {
discountProductMapper.deleteBatchIds(deleteIds);
}
// 计算新增的记录
List<DiscountProductDO> 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<DiscountActivityBaseVO.Product> products) {
if (CollUtil.isEmpty(products)) {
return;
}
// 查询商品参加的活动
List<DiscountProductDetailBO> 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<DiscountProductDetailBO> getRewardProductListBySkuIds(Collection<Long> skuIds,
Collection<Integer> statuses) {
// 查询商品
List<DiscountProductDO> products = discountProductMapper.selectListBySkuId(skuIds);
if (CollUtil.isEmpty(products)) {
return new ArrayList<>(0);
}
// 查询活动
List<DiscountActivityDO> activities = discountActivityMapper.selectBatchIds(skuIds);
activities.removeIf(activity -> !statuses.contains(activity.getStatus())); // 移除不满足 statuses 状态的
Map<Long, DiscountActivityDO> 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<DiscountActivityDO> getDiscountActivityPage(DiscountActivityPageReqVO pageReqVO) {
return discountActivityMapper.selectPage(pageReqVO);
}
@Override
public List<DiscountProductDO> getDiscountProductsByActivityId(Long activityId) {
return discountProductMapper.selectListByActivityId(activityId);
}
}

View File

@ -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<Long, DiscountProductDO> getMatchDiscountProducts(Collection<Long> skuIds);
}

View File

@ -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<Long, DiscountProductDO> getMatchDiscountProducts(Collection<Long> skuIds) {
Map<Long, DiscountProductDO> products = new HashMap<>();
products.put(1L, new DiscountProductDO().setPromotionPrice(100));
products.put(2L, new DiscountProductDO().setPromotionPrice(50));
return products;
}
}

View File

@ -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;
}

View File

@ -4,22 +4,20 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; 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.convert.price.PriceConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; 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.dal.dataobject.reward.RewardActivityDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.*;
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.service.coupon.CouponService; 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.discount.DiscountActivityService;
import cn.iocoder.yudao.module.promotion.service.reward.RewardService; import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; 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.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.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; 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.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
/** /**
@ -54,12 +51,13 @@ import static java.util.Collections.singletonList;
*/ */
@Service @Service
@Validated @Validated
@Slf4j
public class PriceServiceImpl implements PriceService { public class PriceServiceImpl implements PriceService {
@Resource @Resource
private DiscountService discountService; private DiscountActivityService discountService;
@Resource @Resource
private RewardService rewardService; private RewardActivityService rewardActivityService;
@Resource @Resource
private CouponService couponService; private CouponService couponService;
@ -79,7 +77,13 @@ public class PriceServiceImpl implements PriceService {
calculatePriceForOrderLevel(calculateReqDTO.getUserId(), priceCalculate); calculatePriceForOrderLevel(calculateReqDTO.getUserId(), priceCalculate);
// 计算优惠劵级别的价格 // 计算优惠劵级别的价格
calculatePriceForCouponLevel(calculateReqDTO.getUserId(), calculateReqDTO.getCouponId(), 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; return priceCalculate;
} }
@ -115,24 +119,20 @@ public class PriceServiceImpl implements PriceService {
private void calculatePriceForSkuLevel(Long userId, PriceCalculateRespDTO priceCalculate) { private void calculatePriceForSkuLevel(Long userId, PriceCalculateRespDTO priceCalculate) {
// 获取 SKU 级别的所有优惠信息 // 获取 SKU 级别的所有优惠信息
Supplier<Double> memberDiscountPercentSupplier = getMemberDiscountPercentSupplier(userId); Supplier<Double> memberDiscountPercentSupplier = getMemberDiscountPercentSupplier(userId);
Map<Long, DiscountProductDO> discountProducts = discountService.getMatchDiscountProducts( Map<Long, DiscountProductDetailBO> discountProducts = discountService.getMatchDiscountProducts(
convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSkuId)); convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSkuId));
// 处理每个 SKU 的优惠 // 处理每个 SKU 的优惠
priceCalculate.getOrder().getItems().forEach(orderItem -> { priceCalculate.getOrder().getItems().forEach(orderItem -> {
// 获取该 SKU 的优惠信息 // 获取该 SKU 的优惠信息
Double memberDiscountPercent = memberDiscountPercentSupplier.get(); Double memberDiscountPercent = memberDiscountPercentSupplier.get();
DiscountProductDO discountProduct = discountProducts.get(orderItem.getSkuId()); DiscountProductDetailBO discountProduct = discountProducts.get(orderItem.getSkuId());
if (discountProduct != null // 假设优惠价格更贵则认为没优惠
&& discountProduct.getPromotionPrice() >= orderItem.getOriginalUnitPrice()) {
discountProduct = null;
}
if (memberDiscountPercent == null && discountProduct == null) { if (memberDiscountPercent == null && discountProduct == null) {
return; return;
} }
// 计算价格判断选择哪个折扣 // 计算价格判断选择哪个折扣
Integer memberPrice = memberDiscountPercent != null ? (int) (orderItem.getPayPrice() * memberDiscountPercent / 100) : null; 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) { if (memberPrice == null) {
calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice); calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice);
} else if (promotionPrice == null) { } 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, private void calculatePriceByMemberDiscount(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem,
Integer memberPrice) { Integer memberPrice) {
// 记录优惠明细 // 记录优惠明细
@ -156,7 +169,7 @@ public class PriceServiceImpl implements PriceService {
} }
private void calculatePriceByDiscountActivity(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem, private void calculatePriceByDiscountActivity(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem,
DiscountProductDO discountProduct, Integer promotionPrice) { DiscountProductDetailBO discountProduct, Integer promotionPrice) {
// 记录优惠明细 // 记录优惠明细
addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(), addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(),
PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), PromotionLevelEnum.SKU.getLevel(), promotionPrice, PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), PromotionLevelEnum.SKU.getLevel(), promotionPrice,
@ -191,7 +204,7 @@ public class PriceServiceImpl implements PriceService {
private void calculatePriceForOrderLevel(Long userId, PriceCalculateRespDTO priceCalculate) { private void calculatePriceForOrderLevel(Long userId, PriceCalculateRespDTO priceCalculate) {
// 获取 SKU 级别的所有优惠信息 // 获取 SKU 级别的所有优惠信息
Set<Long> spuIds = convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSpuId); Set<Long> spuIds = convertSet(priceCalculate.getOrder().getItems(), PriceCalculateRespDTO.OrderItem::getSpuId);
Map<RewardActivityDO, Set<Long>> rewardActivities = rewardService.getMatchRewardActivities(spuIds); Map<RewardActivityDO, Set<Long>> rewardActivities = rewardActivityService.getMatchRewardActivities(spuIds);
// 处理满减送活动 // 处理满减送活动
if (CollUtil.isNotEmpty(rewardActivities)) { if (CollUtil.isNotEmpty(rewardActivities)) {
@ -216,7 +229,6 @@ public class PriceServiceImpl implements PriceService {
} }
// 分摊金额 // 分摊金额
// TODO 芋艿limit 不能超过最大价格
List<Integer> discountPartPrices = dividePrice(orderItems, rule.getDiscountPrice()); List<Integer> discountPartPrices = dividePrice(orderItems, rule.getDiscountPrice());
// 记录优惠明细 // 记录优惠明细
addPromotion(priceCalculate, orderItems, rewardActivity.getId(), rewardActivity.getName(), 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); Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
assert originPrice != null; assert originPrice != null;
if (originPrice < coupon.getPriceAvailable()) { if (originPrice < coupon.getUsePrice()) {
throw exception(COUPON_NO_MATCH_MIN_PRICE); throw exception(COUPON_NO_MATCH_MIN_PRICE);
} }
@ -291,10 +303,9 @@ public class PriceServiceImpl implements PriceService {
priceCalculate.getOrder().setCouponId(couponId); priceCalculate.getOrder().setCouponId(couponId);
Integer couponPrice = getCouponPrice(coupon, originPrice); Integer couponPrice = getCouponPrice(coupon, originPrice);
// 分摊金额 // 分摊金额
// TODO 芋艿limit 不能超过最大价格
List<Integer> couponPartPrices = dividePrice(orderItems, couponPrice); List<Integer> 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, PromotionTypeEnum.COUPON.getType(), PromotionLevelEnum.COUPON.getLevel(), couponPartPrices,
true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice))); true, StrUtil.format("优惠劵:省 {} 元", formatPrice(couponPrice)));
// 修改 SKU 的分摊 // 修改 SKU 的分摊
@ -309,19 +320,18 @@ public class PriceServiceImpl implements PriceService {
return priceCalculate.getOrder().getItems(); return priceCalculate.getOrder().getItems();
} }
return CollectionUtils.filterList(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) { private Integer getCouponPrice(CouponDO coupon, Integer originPrice) {
// TODO 芋艿 getPreferentialType 的枚举判断 if (PromotionDiscountTypeEnum.PRICE.getType().equals(coupon.getDiscountType())) { // 减价
if (coupon.getPreferentialType().equals(1)) { // 减价 return coupon.getDiscountPrice();
return coupon.getPriceOff(); } else if (PromotionDiscountTypeEnum.PERCENT.getType().equals(coupon.getDiscountType())) { // 打折
} else if (coupon.getPreferentialType().equals(2)) { // 打折 int couponPrice = originPrice * coupon.getDiscountPercent() / 100;
Integer couponPrice = originPrice * coupon.getPercentOff() / 100; return coupon.getDiscountLimitPrice() == null ? couponPrice
return coupon.getDiscountPriceLimit() == null ? couponPrice : Math.min(couponPrice, coupon.getDiscountLimitPrice()); // 优惠上限
: Math.min(couponPrice, coupon.getDiscountPriceLimit()); // 优惠上限
} }
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, private void modifyOrderItemPayPrice(PriceCalculateRespDTO.OrderItem orderItem, Integer newPayPrice,
PriceCalculateRespDTO priceCalculate) { PriceCalculateRespDTO priceCalculate) {
// diffPayPrice 等于额外增加的商品级的优惠
int diffPayPrice = orderItem.getPayPrice() - newPayPrice; int diffPayPrice = orderItem.getPayPrice() - newPayPrice;
// 设置 OrderItem 价格相关字段 // 设置 OrderItem 价格相关字段
orderItem.setDiscountPrice(orderItem.getDiscountPrice() + diffPayPrice); orderItem.setDiscountPrice(orderItem.getDiscountPrice() + diffPayPrice);
orderItem.setPayPrice(newPayPrice); orderItem.setPayPrice(newPayPrice);
orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice()); orderItem.setOrderDividePrice(orderItem.getPayPrice() - orderItem.getOrderPartPrice());
// 设置 Order 相关相关字段 // 设置 Order 相关相关字段
priceCalculate.getOrder().setPayPrice(priceCalculate.getOrder().getPayPrice() - diffPayPrice); PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
order.setPayPrice(order.getPayPrice() - diffPayPrice);
order.setOrderPrice(order.getOrderPrice() - diffPayPrice);
} }
/** /**

View File

@ -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<RewardActivityDO> getRewardActivityPage(RewardActivityPageReqVO pageReqVO);
/**
* 基于指定的 SPU 编号数组获得它们匹配的满减送活动
*
* @param spuIds SPU 编号数组
* @return 满减送活动与对应的 SPU 编号的映射value 就是 SPU 编号的集合
*/
Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds);
}

View File

@ -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<Long> spuIds) {
if (CollUtil.isEmpty(spuIds)) {
return;
}
// 查询商品参加的活动
List<RewardActivityDO> 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<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds,
Collection<Integer> statuses) {
List<RewardActivityDO> 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<RewardActivityDO> getRewardActivityPage(RewardActivityPageReqVO pageReqVO) {
return rewardActivityMapper.selectPage(pageReqVO);
}
@Override
public Map<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds) {
// 如果有全局活动则直接选择它
List<RewardActivityDO> allActivities = rewardActivityMapper.selectListByProductScopeAndStatus(
PromotionProductScopeEnum.ALL.getScope(), PromotionActivityStatusEnum.RUN.getStatus());
if (CollUtil.isNotEmpty(allActivities)) {
return MapUtil.builder(allActivities.get(0), spuIds).build();
}
// 查询某个活动参加的活动
List<RewardActivityDO> productActivityList = getRewardActivityListBySpuIds(spuIds,
singleton(PromotionActivityStatusEnum.RUN.getStatus()));
return convertMap(productActivityList, activity -> activity,
rewardActivityDO -> intersectionDistinct(rewardActivityDO.getProductSpuIds(), spuIds)); // 求交集返回
}
}

View File

@ -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<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds);
}

View File

@ -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<RewardActivityDO, Set<Long>> getMatchRewardActivities(Set<Long> spuIds) {
return Collections.emptyMap();
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper">
<update id="updateTakeCount">
UPDATE promotion_coupon_template
SET take_count = take_count + #{incrCount}
WHERE id = #{id}
</update>
</mapper>

View File

@ -1,19 +1,24 @@
package cn.iocoder.yudao.module.promotion.service.coupon; 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.common.pojo.PageResult;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 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.template.CouponTemplateCreateReqVO;
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.controller.admin.coupon.vo.CouponTemplateUpdateReqVO; 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.dataobject.coupon.CouponTemplateDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.coupon.CouponTemplateMapper; 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.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Date; 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.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.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
@ -39,7 +44,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest {
@Test @Test
public void testCreateCouponTemplate_success() { 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); Long couponTemplateId = couponTemplateService.createCouponTemplate(reqVO);
@ -58,6 +66,10 @@ public class CouponTemplateServiceImplTest extends BaseDbUnitTest {
// 准备参数 // 准备参数
CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> { CouponTemplateUpdateReqVO reqVO = randomPojo(CouponTemplateUpdateReqVO.class, o -> {
o.setId(dbCouponTemplate.getId()); // 设置更新的 ID 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 @Test
@Disabled // TODO 请修改 null 为需要的值然后删除 @Disabled 注解
public void testGetCouponTemplatePage() { public void testGetCouponTemplatePage() {
// mock 数据 // mock 数据
CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class, o -> { // 等会查询到 CouponTemplateDO dbCouponTemplate = randomPojo(CouponTemplateDO.class, o -> { // 等会查询到
o.setName(null); o.setName("芋艿");
o.setStatus(null); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setDiscountType(null); o.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType());
o.setCreateTime(null); o.setCreateTime(buildTime(2022, 2, 2));
}); });
couponTemplateMapper.insert(dbCouponTemplate); couponTemplateMapper.insert(dbCouponTemplate);
// 测试 name 不匹配 // 测试 name 不匹配
couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setName(null))); couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setName("土豆")));
// 测试 status 不匹配 // 测试 status 不匹配
couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setStatus(null))); couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
// 测试 type 不匹配 // 测试 type 不匹配
couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setDiscountType(null))); couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setDiscountType(PromotionDiscountTypeEnum.PRICE.getType())));
// 测试 createTime 不匹配 // 测试 createTime 不匹配
couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setCreateTime(null))); couponTemplateMapper.insert(cloneIgnoreId(dbCouponTemplate, o -> o.setCreateTime(buildTime(2022, 1, 1))));
// 准备参数 // 准备参数
CouponTemplatePageReqVO reqVO = new CouponTemplatePageReqVO(); CouponTemplatePageReqVO reqVO = new CouponTemplatePageReqVO();
reqVO.setName(null); reqVO.setName("芋艿");
reqVO.setStatus(null); reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setDiscountType(null); reqVO.setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType());
reqVO.setCreateTime((new Date[]{})); reqVO.setCreateTime((new Date[]{buildTime(2022, 2, 1), buildTime(2022, 2, 3)}));
// 调用 // 调用
PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage(reqVO); PageResult<CouponTemplateDO> pageResult = couponTemplateService.getCouponTemplatePage(reqVO);

View File

@ -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<DiscountProductDO> 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<DiscountProductDO> 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<DiscountActivityDO> pageResult = discountActivityService.getDiscountActivityPage(reqVO);
// 断言
assertEquals(1, pageResult.getTotal());
assertEquals(1, pageResult.getList().size());
assertPojoEquals(dbDiscountActivity, pageResult.getList().get(0));
}
}

View File

@ -2,20 +2,17 @@ package cn.iocoder.yudao.module.promotion.service.price;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; 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.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; 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.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.dal.dataobject.reward.RewardActivityDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; import cn.iocoder.yudao.module.promotion.enums.common.*;
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.service.coupon.CouponService; 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.discount.DiscountActivityService;
import cn.iocoder.yudao.module.promotion.service.reward.RewardService; import cn.iocoder.yudao.module.promotion.service.discount.bo.DiscountProductDetailBO;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
@ -44,9 +41,9 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
private PriceServiceImpl priceService; private PriceServiceImpl priceService;
@Mock @Mock
private DiscountService discountService; private DiscountActivityService discountService;
@Mock @Mock
private RewardService rewardService; private RewardActivityService rewardActivityService;
@Mock @Mock
private CouponService couponService; private CouponService couponService;
@Mock @Mock
@ -67,6 +64,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
// 断言 Order 部分 // 断言 Order 部分
PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
assertEquals(order.getOriginalPrice(), 200); assertEquals(order.getOriginalPrice(), 200);
assertEquals(order.getOrderPrice(), 180);
assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getDiscountPrice(), 0);
assertEquals(order.getPointPrice(), 0); assertEquals(order.getPointPrice(), 0);
assertEquals(order.getDeliveryPrice(), 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)); ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50));
when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02)); when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02));
// mock 方法限时折扣 DiscountActivity 信息 // mock 方法限时折扣 DiscountActivity 信息
DiscountProductDO discountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(1000L).setActivityName("活动 1000 号") DiscountProductDetailBO discountProduct01 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(1000L)
.setSkuId(10L).setPromotionPrice(80)); .setActivityName("活动 1000 号").setSkuId(10L)
DiscountProductDO discountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(2000L).setActivityName("活动 2000 号") .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(40));
.setSkuId(20L).setPromotionPrice(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( when(discountService.getMatchDiscountProducts(eq(asSet(10L, 20L)))).thenReturn(
MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map()); MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map());
// 10L: 100 * 2 - 40 * 2 = 120
// 20L50 * 3 - 50 * 3 * 0.4 = 90
// 调用 // 调用
PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
// 断言 Order 部分 // 断言 Order 部分
PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
assertEquals(order.getOriginalPrice(), 350); assertEquals(order.getOriginalPrice(), 350);
assertEquals(order.getOrderPrice(), 210);
assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getDiscountPrice(), 0);
assertEquals(order.getPointPrice(), 0); assertEquals(order.getPointPrice(), 0);
assertEquals(order.getDeliveryPrice(), 0); assertEquals(order.getDeliveryPrice(), 0);
assertEquals(order.getPayPrice(), 280); assertEquals(order.getPayPrice(), 210);
assertNull(order.getCouponId()); assertNull(order.getCouponId());
// 断言 OrderItem 部分 // 断言 OrderItem 部分
assertEquals(order.getItems().size(), 2); assertEquals(order.getItems().size(), 2);
@ -136,19 +140,19 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
assertEquals(orderItem01.getCount(), 2); assertEquals(orderItem01.getCount(), 2);
assertEquals(orderItem01.getOriginalPrice(), 200); assertEquals(orderItem01.getOriginalPrice(), 200);
assertEquals(orderItem01.getOriginalUnitPrice(), 100); assertEquals(orderItem01.getOriginalUnitPrice(), 100);
assertEquals(orderItem01.getDiscountPrice(), 40); assertEquals(orderItem01.getDiscountPrice(), 80);
assertEquals(orderItem01.getPayPrice(), 160); assertEquals(orderItem01.getPayPrice(), 120);
assertEquals(orderItem01.getOrderPartPrice(), 0); assertEquals(orderItem01.getOrderPartPrice(), 0);
assertEquals(orderItem01.getOrderDividePrice(), 160); assertEquals(orderItem01.getOrderDividePrice(), 120);
PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1); PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1);
assertEquals(orderItem02.getSkuId(), 20L); assertEquals(orderItem02.getSkuId(), 20L);
assertEquals(orderItem02.getCount(), 3); assertEquals(orderItem02.getCount(), 3);
assertEquals(orderItem02.getOriginalPrice(), 150); assertEquals(orderItem02.getOriginalPrice(), 150);
assertEquals(orderItem02.getOriginalUnitPrice(), 50); assertEquals(orderItem02.getOriginalUnitPrice(), 50);
assertEquals(orderItem02.getDiscountPrice(), 30); assertEquals(orderItem02.getDiscountPrice(), 60);
assertEquals(orderItem02.getPayPrice(), 120); assertEquals(orderItem02.getPayPrice(), 90);
assertEquals(orderItem02.getOrderPartPrice(), 0); assertEquals(orderItem02.getOrderPartPrice(), 0);
assertEquals(orderItem02.getOrderDividePrice(), 120); assertEquals(orderItem02.getOrderDividePrice(), 90);
// 断言 Promotion 部分 // 断言 Promotion 部分
assertEquals(priceCalculate.getPromotions().size(), 2); assertEquals(priceCalculate.getPromotions().size(), 2);
PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0); 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.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType());
assertEquals(promotion01.getLevel(), PromotionLevelEnum.SKU.getLevel()); assertEquals(promotion01.getLevel(), PromotionLevelEnum.SKU.getLevel());
assertEquals(promotion01.getOriginalPrice(), 200); assertEquals(promotion01.getOriginalPrice(), 200);
assertEquals(promotion01.getDiscountPrice(), 40); assertEquals(promotion01.getDiscountPrice(), 80);
assertTrue(promotion01.getMeet()); assertTrue(promotion01.getMeet());
assertEquals(promotion01.getMeetTip(), "限时折扣:省 0.40 元"); assertEquals(promotion01.getMeetTip(), "限时折扣:省 0.80 元");
PriceCalculateRespDTO.PromotionItem promotionItem01 = promotion01.getItems().get(0); PriceCalculateRespDTO.PromotionItem promotionItem01 = promotion01.getItems().get(0);
assertEquals(promotion01.getItems().size(), 1); assertEquals(promotion01.getItems().size(), 1);
assertEquals(promotionItem01.getSkuId(), 10L); assertEquals(promotionItem01.getSkuId(), 10L);
assertEquals(promotionItem01.getOriginalPrice(), 200); assertEquals(promotionItem01.getOriginalPrice(), 200);
assertEquals(promotionItem01.getDiscountPrice(), 40); assertEquals(promotionItem01.getDiscountPrice(), 80);
PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1); PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1);
assertEquals(promotion02.getId(), 2000L); assertEquals(promotion02.getId(), 2000L);
assertEquals(promotion02.getName(), "活动 2000 号"); assertEquals(promotion02.getName(), "活动 2000 号");
assertEquals(promotion02.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); assertEquals(promotion02.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType());
assertEquals(promotion02.getLevel(), PromotionLevelEnum.SKU.getLevel()); assertEquals(promotion02.getLevel(), PromotionLevelEnum.SKU.getLevel());
assertEquals(promotion02.getOriginalPrice(), 150); assertEquals(promotion02.getOriginalPrice(), 150);
assertEquals(promotion02.getDiscountPrice(), 30); assertEquals(promotion02.getDiscountPrice(), 60);
assertTrue(promotion02.getMeet()); assertTrue(promotion02.getMeet());
assertEquals(promotion02.getMeetTip(), "限时折扣:省 0.30 元"); assertEquals(promotion02.getMeetTip(), "限时折扣:省 0.60 元");
PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0); PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0);
assertEquals(promotion02.getItems().size(), 1); assertEquals(promotion02.getItems().size(), 1);
assertEquals(promotionItem02.getSkuId(), 20L); assertEquals(promotionItem02.getSkuId(), 20L);
assertEquals(promotionItem02.getOriginalPrice(), 150); assertEquals(promotionItem02.getOriginalPrice(), 150);
assertEquals(promotionItem02.getDiscountPrice(), 30); assertEquals(promotionItem02.getDiscountPrice(), 60);
} }
/** /**
@ -208,13 +212,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>(); Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>();
matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); matchRewardActivities.put(rewardActivity01, asSet(1L, 2L));
matchRewardActivities.put(rewardActivity02, asSet(3L)); 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); PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
// 断言 Order 部分 // 断言 Order 部分
PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
assertEquals(order.getOriginalPrice(), 470); assertEquals(order.getOriginalPrice(), 470);
assertEquals(order.getOrderPrice(), 470);
assertEquals(order.getDiscountPrice(), 130); assertEquals(order.getDiscountPrice(), 130);
assertEquals(order.getPointPrice(), 0); assertEquals(order.getPointPrice(), 0);
assertEquals(order.getDeliveryPrice(), 0); assertEquals(order.getDeliveryPrice(), 0);
@ -305,13 +310,14 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
.setRules(singletonList(new RewardActivityDO.Rule().setLimit(351).setDiscountPrice(70)))); .setRules(singletonList(new RewardActivityDO.Rule().setLimit(351).setDiscountPrice(70))));
Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>(); Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>();
matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); 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); PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
// 断言 Order 部分 // 断言 Order 部分
PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
assertEquals(order.getOriginalPrice(), 350); assertEquals(order.getOriginalPrice(), 350);
assertEquals(order.getOrderPrice(), 350);
assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getDiscountPrice(), 0);
assertEquals(order.getPointPrice(), 0); assertEquals(order.getPointPrice(), 0);
assertEquals(order.getDeliveryPrice(), 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)); 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)); when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03));
// mock 方法优惠劵 Coupon 信息 // mock 方法优惠劵 Coupon 信息
CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setTitle("程序员节") CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setName("程序员节")
.setProductScope(PromotionProductScopeEnum.SPU.getScope()).setSpuIds(asList(1L, 2L)) .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L))
.setPriceAvailable(350).setPreferentialType(2).setPercentOff(50).setDiscountPriceLimit(70)); .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType())
.setDiscountPercent(50).setDiscountLimitPrice(70));
when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon); when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon);
// 200 + 150; 350
//
// 调用 // 调用
PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO);
// 断言 Order 部分 // 断言 Order 部分
PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); PriceCalculateRespDTO.Order order = priceCalculate.getOrder();
assertEquals(order.getOriginalPrice(), 470); assertEquals(order.getOriginalPrice(), 470);
assertEquals(order.getOrderPrice(), 470);
assertEquals(order.getDiscountPrice(), 0); assertEquals(order.getDiscountPrice(), 0);
assertEquals(order.getPointPrice(), 0); assertEquals(order.getPointPrice(), 0);
assertEquals(order.getDeliveryPrice(), 0); assertEquals(order.getDeliveryPrice(), 0);

View File

@ -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<RewardActivityDO> 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<Long> spuIds = asSet(1L, 2L);
// 调用
Map<RewardActivityDO, Set<Long>> matchRewardActivities = rewardActivityService.getMatchRewardActivities(spuIds);
// 断言
assertEquals(matchRewardActivities.size(), 1);
Map.Entry<RewardActivityDO, Set<Long>> 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<Long> spuIds = asSet(1L, 2L, 3L);
// 调用
Map<RewardActivityDO, Set<Long>> 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();
}
});
}
}

View File

@ -1 +1,6 @@
DELETE FROM "market_activity"; 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";

View File

@ -17,3 +17,108 @@ CREATE TABLE IF NOT EXISTS "market_activity" (
"tenant_id" bigint(20) NOT NULL, "tenant_id" bigint(20) NOT NULL,
PRIMARY KEY ("id") PRIMARY KEY ("id")
) COMMENT '促销活动'; ) 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 '限时折扣活动';

View File

@ -43,13 +43,12 @@ public class AppTradeOrderController {
@PreAuthenticated @PreAuthenticated
public CommonResult<Long> createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, public CommonResult<Long> createTradeOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO,
HttpServletRequest servletRequest) { HttpServletRequest servletRequest) {
// 获取登录用户 // 获取登录用户用户 IP 地址
Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
// 获取用户ip地址
String clientIp = ServletUtil.getClientIP(servletRequest); String clientIp = ServletUtil.getClientIP(servletRequest);
// 创建交易订单预支付记录 // 创建交易订单预支付记录
Long result = tradeOrderService.createTradeOrder(loginUserId, clientIp, createReqVO); Long orderId = tradeOrderService.createTradeOrder(loginUserId, clientIp, createReqVO);
return CommonResult.success(result); return CommonResult.success(orderId);
} }
@GetMapping("/get") @GetMapping("/get")

View File

@ -19,7 +19,7 @@ public class AppTradeOrderCreateReqVO {
@ApiModelProperty(name = "优惠劵编号", example = "1024") @ApiModelProperty(name = "优惠劵编号", example = "1024")
private Long couponId; private Long couponId;
@ApiModelProperty(name = "备注", example = "1024") @ApiModelProperty(name = "备注", example = "这个是我的订单哟")
private String remark; private String remark;
@ApiModelProperty(name = "是否来自购物车", required = true, example = "true", notes = "true - 来自购物车false - 立即购买") @ApiModelProperty(name = "是否来自购物车", required = true, example = "true", notes = "true - 来自购物车false - 立即购买")

View File

@ -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.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 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.TradeOrderCancelTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum; 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()} 求和 * 基于 {@link TradeOrderItemDO#getTotalOriginalPrice()} 求和
*
* 对应 taobao trade.total_fee 字段
*/ */
private Integer originalPrice; 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 OrderItem#getPayPrice()} 求和
* + {@link #deliveryPrice}
* + {@link #adjustPrice}
* - {@link #promotionPrice}
* - {@link #couponPrice} * - {@link #couponPrice}
* - {@link #pointPrice} * - {@link #pointPrice}
* + {@link #deliveryPrice}
* - {@link #discountPrice}
* + {@link #adjustPrice}
*/ */
private Integer payPrice; private Integer payPrice;
/** /**
@ -164,11 +176,11 @@ public class TradeOrderDO extends BaseDO {
* *
* 关联 DeliveryTemplateDO id 编号 * 关联 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; private Long couponId;
/** /**
* 优惠劵减免金额单位 * 优惠劵减免金额单位
*
* 对应 taobao trade.coupon_fee 字段
*/ */
private Integer couponPrice; private Integer couponPrice;
/** /**
* 积分抵扣的金额单位 * 积分抵扣的金额单位
*
* 对应 taobao trade.point_fee 字段
*/ */
private Integer pointPrice; private Integer pointPrice;

View File

@ -71,7 +71,7 @@ public class TradeOrderItemDO extends BaseDO {
*/ */
private Integer count; private Integer count;
/** /**
* 是否评论 * 是否评论 TODO
* *
* false - 未评论 * false - 未评论
* true - 已评论 * true - 已评论
@ -79,61 +79,61 @@ public class TradeOrderItemDO extends BaseDO {
private Boolean commented; private Boolean commented;
// ========== 价格 + 支付基本信息 ========== // ========== 价格 + 支付基本信息 ==========
/**
* 商品原价单位
*
* = {@link #originalUnitPrice} * {@link #getCount()}
*/
private Integer originalPrice;
/** /**
* 商品原价单位 * 商品原价单位
* *
* 对应 ProductSkuDO price 字段 * 对应 ProductSkuDO price 字段
* 对应 taobao order.price 字段
*/ */
// like - original_priceniu - costPrice private Integer originalUnitPrice;
private Integer originalPrice;
/** /**
* 商品原价单位 * 商品优惠单位
* *
* = {@link #originalPrice} * {@link #count} * 商品级优惠对单个商品的常见如商品原价的 8 商品原价的减 50
*/
// like - total_priceniu - 暂无
private Integer totalOriginalPrice;
/**
* 商品级优惠单位
* *
* 例如说限时折扣商品原价的 8 商品原价的减 50 * 对应 taobao order.discount_fee 字段
*/ */
// taobao - order.discount_fee子订单商品优惠 private Integer discountPrice;
private Integer totalPromotionPrice;
/** /**
* 最终购买金额单位 * 子订单实付金额不算主订单分摊金额单位
* *
* = {@link #totalPresentPrice} / {@link #count} * = {@link #originalPrice}
*/ * - {@link #discountPrice}
private Integer presentPrice;
/**
* 最终购买金额单位
* *
* = {@link #totalOriginalPrice} * 对应 taobao order.payment 字段
* - {@link #totalPromotionPrice}
*/ */
// like - total_pay_priceniu - goods_money; taobao - order.payment子订单实付金额不算主订单分摊金额 | order.total_fee子订单应付金额参考使用 private Integer payPrice;
private Integer totalPresentPrice;
// TODO 芋艿part_mjz_discount(子订单分摊金额)本质上totalOriginalPrice - totalPayPrice
/** /**
* 应付金额单位 * 子订单分摊金额单位
* 需要分摊 {@link TradeOrderDO#getDiscountPrice()}{@link TradeOrderDO#getCouponPrice()}{@link TradeOrderDO#getPointPrice()}
*
* 对应 taobao order.part_mjz_discount 字段
* 淘宝说明子订单分摊优惠基础逻辑一般正常优惠券和满减优惠按照子订单的金额进行分摊特殊情况如果优惠券是指定商品使用的只会分摊到对应商品子订单上不分摊
*/ */
// taobao - divide_order_fee 分摊后子订单实付金额 private Integer orderPartPrice;
private Integer totalPayPrice; /**
* 分摊后子订单实付金额单位
*
* = {@link #payPrice}
* - {@link #orderPartPrice}
*
* 对应 taobao divide_order_fee 字段
*/
private Integer orderDividePrice;
// ========== 营销基本信息 ========== // ========== 营销基本信息 ==========
// /**
// * 积分抵扣的金额单位
// */
// private Integer integralTotal; // like - integral_priceniu - point_money
// /**
// * 使用的积分
// */
// private Integer useIntegral; // niu - use_point
// ========== 退款基本信息 ========== // ========== 退款基本信息 ==========
/** /**
* 退款状态 * 退款状态 TODO
* *
* 枚举 {@link TradeOrderItemRefundStatusEnum} * 枚举 {@link TradeOrderItemRefundStatusEnum}
*/ */
@ -148,7 +148,7 @@ public class TradeOrderItemDO extends BaseDO {
// presentTotal = buyTotal - discountTotal = 24 - 11 = 13 // presentTotal = buyTotal - discountTotal = 24 - 11 = 13
// 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33
/** /**
* 退款总金额单位 * 退款总金额单位 TODO
*/ */
private Integer refundTotal; 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 一堆退款字段
} }

View File

@ -3,18 +3,20 @@ package cn.iocoder.yudao.module.trade.service.order;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
/** /**
* TODO @LeeYan9: 类注释 * 交易订单 Service 接口
*
* @author LeeYan9 * @author LeeYan9
* @since 2022-08-26 * @since 2022-08-26
*/ */
public interface TradeOrderService { public interface TradeOrderService {
/** /**
* 创建交易订单 TODO @LeeYan9: 方法注释, 和参数要空一行 * 创建交易订单
*
* @param loginUserId 登录用户 * @param loginUserId 登录用户
* @param clientIp 用户ip地址 // TODO @LeeYan9: 中英文之间, 空一行哈 * @param clientIp 用户 IP 地址
* @param createReqVO 创建交易订单请求模型 * @param createReqVO 创建交易订单请求模型
* @return 交易订单创建结果 * @return 交易订单的编号
*/ */
Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO); Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO);
} }

View File

@ -45,14 +45,17 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
* TODO @LeeYan9: 注释 * 交易订单 Service 实现类
*
* @author LeeYan9 * @author LeeYan9
* @since 2022-08-26 * @since 2022-08-26
*/ */
@Service @Service
public class TradeOrderServiceImpl implements TradeOrderService { 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 @Resource
private TradeOrderMapper tradeOrderMapper; private TradeOrderMapper tradeOrderMapper;
@ -71,15 +74,10 @@ public class TradeOrderServiceImpl implements TradeOrderService {
@Resource @Resource
private TradeOrderProperties tradeOrderProperties; private TradeOrderProperties tradeOrderProperties;
// TODO LeeYan9: 静态变量, 需要在最前面哈; 另外, 静态变量的注释最好写下;
private static final String BLANK_PLACEHOLDER = " ";
private static final String MULTIPLIER_PLACEHOLDER = "x";
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) {
List<Item> items = createReqVO.getItems();
List<Item> items = createReqVO.getItems(); // TODO @LeeYan9: 方法第一行, 不用空哈;
// 商品SKU检查 sku可售状态,库存 // 商品SKU检查 sku可售状态,库存
List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId)); List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId));
Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId); Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId);

View File

@ -2,6 +2,12 @@ package cn.iocoder.yudao.module.member.api.user;
import cn.iocoder.yudao.module.member.api.user.dto.UserRespDTO; 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 接口 * 会员用户的 API 接口
* *
@ -17,4 +23,30 @@ public interface MemberUserApi {
*/ */
UserRespDTO getUser(Long id); UserRespDTO getUser(Long id);
/**
* 获得会员用户信息们
*
* @param ids 用户编号的数组
* @return 用户信息们
*/
List<UserRespDTO> getUsers(Collection<Long> ids);
/**
* 获得会员用户 Map
*
* @param ids 用户编号的数组
* @return 会员用户 Map
*/
default Map<Long, UserRespDTO> getUserMap(Collection<Long> ids) {
return convertMap(getUsers(ids), UserRespDTO::getId);
}
/**
* 基于用户昵称模糊匹配用户列表
*
* @param nickname 用户昵称模糊匹配
* @return 用户信息的列表
*/
List<UserRespDTO> getUserListByNickname(String nickname);
} }

View File

@ -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;
}

View File

@ -8,6 +8,8 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
/** /**
* 会员用户的 API 实现类 * 会员用户的 API 实现类
@ -27,4 +29,14 @@ public class MemberUserApiImpl implements MemberUserApi {
return UserConvert.INSTANCE.convert2(user); return UserConvert.INSTANCE.convert2(user);
} }
@Override
public List<UserRespDTO> getUsers(Collection<Long> ids) {
return UserConvert.INSTANCE.convertList2(userService.getUserList(ids));
}
@Override
public List<UserRespDTO> getUserListByNickname(String nickname) {
return UserConvert.INSTANCE.convertList2(userService.getUserListByNickname(nickname));
}
} }

View File

@ -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<UserInfoDTO> getUserInfo(@PathVariable String tel){
MemberUserDO user = userService.getUserByMobile(tel);
return CommonResult.success(UserConvert.INSTANCE.convertInfo(user));
}
}

View File

@ -1,12 +1,13 @@
package cn.iocoder.yudao.module.member.convert.user; 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.api.user.dto.UserRespDTO;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO; import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoRespVO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper @Mapper
public interface UserConvert { public interface UserConvert {
@ -15,5 +16,7 @@ public interface UserConvert {
AppUserInfoRespVO convert(MemberUserDO bean); AppUserInfoRespVO convert(MemberUserDO bean);
UserRespDTO convert2(MemberUserDO bean); UserRespDTO convert2(MemberUserDO bean);
UserInfoDTO convertInfo(MemberUserDO bean);
List<UserRespDTO> convertList2(List<MemberUserDO> list);
} }

View File

@ -1,9 +1,12 @@
package cn.iocoder.yudao.module.member.dal.mysql.user; 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.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO; import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/** /**
* 会员 User Mapper * 会员 User Mapper
* *
@ -16,4 +19,9 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
return selectOne(MemberUserDO::getMobile, mobile); return selectOne(MemberUserDO::getMobile, mobile);
} }
default List<MemberUserDO> selectListByNicknameLike(String nickname) {
return selectList(new LambdaQueryWrapperX<MemberUserDO>()
.likeIfPresent(MemberUserDO::getNickname, nickname));
}
} }

View File

@ -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 cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection;
import java.util.List;
/** /**
* 会员用户 Service 接口 * 会员用户 Service 接口
@ -21,6 +23,15 @@ public interface MemberUserService {
*/ */
MemberUserDO getUserByMobile(String mobile); MemberUserDO getUserByMobile(String mobile);
/**
* 基于用户昵称模糊匹配用户列表
*
* @param nickname 用户昵称模糊匹配
* @return 用户信息的列表
*/
List<MemberUserDO> getUserListByNickname(String nickname);
/** /**
* 基于手机号创建用户 * 基于手机号创建用户
* 如果用户已经存在则直接进行返回 * 如果用户已经存在则直接进行返回
@ -47,6 +58,14 @@ public interface MemberUserService {
*/ */
MemberUserDO getUser(Long id); MemberUserDO getUser(Long id);
/**
* 通过用户 ID 查询用户们
*
* @param ids 用户 ID
* @return 用户对象信息数组
*/
List<MemberUserDO> getUserList(Collection<Long> ids);
/** /**
* 修改用户昵称 * 修改用户昵称
* @param userId 用户id * @param userId 用户id

View File

@ -19,7 +19,9 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection;
import java.util.Date; 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.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
@ -51,6 +53,11 @@ public class MemberUserServiceImpl implements MemberUserService {
return memberUserMapper.selectByMobile(mobile); return memberUserMapper.selectByMobile(mobile);
} }
@Override
public List<MemberUserDO> getUserListByNickname(String nickname) {
return memberUserMapper.selectListByNicknameLike(nickname);
}
@Override @Override
public MemberUserDO createUserIfAbsent(String mobile, String registerIp) { public MemberUserDO createUserIfAbsent(String mobile, String registerIp) {
// 用户已经存在 // 用户已经存在
@ -86,6 +93,11 @@ public class MemberUserServiceImpl implements MemberUserService {
return memberUserMapper.selectById(id); return memberUserMapper.selectById(id);
} }
@Override
public List<MemberUserDO> getUserList(Collection<Long> ids) {
return memberUserMapper.selectBatchIds(ids);
}
@Override @Override
public void updateUserNickname(Long userId, String nickname) { public void updateUserNickname(Long userId, String nickname) {
MemberUserDO user = this.checkUserExists(userId); MemberUserDO user = this.checkUserExists(userId);

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.system.controller.admin.permission.vo.role; 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.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
@ -16,7 +18,7 @@ public class RoleUpdateStatusReqVO {
@ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举") @ApiModelProperty(value = "状态", required = true, example = "1", notes = "见 CommonStatusEnum 枚举")
@NotNull(message = "状态不能为空") @NotNull(message = "状态不能为空")
// @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}")
private Integer status; private Integer status;
} }

View File

@ -174,6 +174,7 @@ logging:
cn.iocoder.yudao.module.tool.dal.mysql: debug cn.iocoder.yudao.module.tool.dal.mysql: debug
cn.iocoder.yudao.module.member.dal.mysql: debug cn.iocoder.yudao.module.member.dal.mysql: debug
cn.iocoder.yudao.module.trade.dal.mysql: debug cn.iocoder.yudao.module.trade.dal.mysql: debug
cn.iocoder.yudao.module.promotion.dal.mysql: debug
--- #################### 微信公众号、小程序相关配置 #################### --- #################### 微信公众号、小程序相关配置 ####################
wx: wx:

View File

@ -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'
})
}

View File

@ -0,0 +1,9 @@
import request from '@/utils/request'
// 获得商品 SKU 选项的列表
export function getSkuOptionList() {
return request({
url: '/product/sku/get-option-list',
method: 'get',
})
}

View File

@ -1,6 +1,6 @@
import request from '@/utils/request' import request from '@/utils/request'
// 创建商品spu // 创建商品 SPU
export function createSpu(data) { export function createSpu(data) {
return request({ return request({
url: '/product/spu/create', url: '/product/spu/create',
@ -9,7 +9,7 @@ export function createSpu(data) {
}) })
} }
// 更新商品spu // 更新商品 SPU
export function updateSpu(data) { export function updateSpu(data) {
return request({ return request({
url: '/product/spu/update', url: '/product/spu/update',
@ -18,7 +18,7 @@ export function updateSpu(data) {
}) })
} }
// 删除商品spu // 删除商品 SPU
export function deleteSpu(id) { export function deleteSpu(id) {
return request({ return request({
url: '/product/spu/delete?id=' + id, url: '/product/spu/delete?id=' + id,
@ -34,7 +34,7 @@ export function getSpu(id) {
}) })
} }
// 获得商品spu详情 // 获得商品 SPU 详情
export function getSpuDetail(id) { export function getSpuDetail(id) {
return request({ return request({
url: '/product/spu/get/detail?id=' + id, url: '/product/spu/get/detail?id=' + id,
@ -42,7 +42,7 @@ export function getSpuDetail(id) {
}) })
} }
// 获得商品spu分页 // 获得商品 SPU 分页
export function getSpuPage(query) { export function getSpuPage(query) {
return request({ return request({
url: '/product/spu/page', url: '/product/spu/page',
@ -50,3 +50,11 @@ export function getSpuPage(query) {
params: query params: query
}) })
} }
// 获得商品 SPU 精简列表
export function getSpuSimpleList() {
return request({
url: '/product/spu/get-simple-list',
method: 'get',
})
}

Some files were not shown because too many files have changed in this diff Show More