promotion:增加限时折扣的基础代码
parent
00f90e75d9
commit
d4b7f4aaa0
|
@ -3,14 +3,19 @@ package cn.iocoder.yudao.module.promotion.enums;
|
|||
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* market 错误码枚举类
|
||||
* <p>
|
||||
* promotion 错误码枚举类
|
||||
*
|
||||
* market 系统,使用 1-003-000-000 段
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 促销活动相关 1003001000 ============ TODO 芋艿:看看是不是要删除掉
|
||||
ErrorCode ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "促销活动不存在");
|
||||
// ========== 促销活动相关 1003001000 ============
|
||||
ErrorCode DISCOUNT_ACTIVITY_NOT_EXISTS = new ErrorCode(1003001000, "限时折扣活动不存在");
|
||||
ErrorCode DISCOUNT_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003006001, "存在商品参加了其它限时折扣活动");
|
||||
ErrorCode DISCOUNT_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED = new ErrorCode(1003006002, "限时折扣活动已关闭,不能修改");
|
||||
ErrorCode DISCOUNT_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED = new ErrorCode(1003006003, "限时折扣活动未关闭,不能删除");
|
||||
ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1003006004, "限时折扣活动已关闭,不能重复关闭");
|
||||
ErrorCode DISCOUNT_ACTIVITY_CLOSE_FAIL_STATUS_END = new ErrorCode(1003006004, "限时折扣活动已结束,不能关闭");
|
||||
|
||||
// ========== Banner 相关 1003002000 ============
|
||||
ErrorCode BANNER_NOT_EXISTS = new ErrorCode(1003002000, "Banner 不存在");
|
||||
|
@ -29,7 +34,7 @@ public interface ErrorCodeConstants {
|
|||
|
||||
// ========== 满减送活动 1003006000 ==========
|
||||
ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1003006000, "满减送活动不存在");
|
||||
ErrorCode REWARD_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1003006001, "商品({}) 已经参加满减送活动({})");
|
||||
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, "满减送活动已关闭,不能重复关闭");
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
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.DiscountActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityPageReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO;
|
||||
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.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 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<DiscountActivityRespVO> getDiscountActivity(@RequestParam("id") Long id) {
|
||||
DiscountActivityDO discountActivity = discountActivityService.getDiscountActivity(id);
|
||||
return success(DiscountActivityConvert.INSTANCE.convert(discountActivity));
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
/**
|
||||
* TODO 占位
|
||||
*/
|
||||
package cn.iocoder.yudao.module.promotion.controller.admin.discount;
|
|
@ -0,0 +1,56 @@
|
|||
package cn.iocoder.yudao.module.promotion.controller.admin.discount.vo;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
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 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 = "1000")
|
||||
@NotNull(message = "折扣价格不能为空")
|
||||
@Min(value = 1, message = "折扣价格必须大于 0")
|
||||
private Integer discountPrice;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
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.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@ApiModel("管理后台 - 限时折扣活动创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class DiscountActivityCreateReqVO extends DiscountActivityBaseVO {
|
||||
|
||||
/**
|
||||
* 商品列表
|
||||
*/
|
||||
@NotNull(message = "商品列表不能为空")
|
||||
private List<Product> products;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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.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;
|
||||
|
||||
/**
|
||||
* 商品列表
|
||||
*/
|
||||
@NotNull(message = "商品列表不能为空")
|
||||
private List<DiscountActivityCreateReqVO.Product> products;
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package cn.iocoder.yudao.module.promotion.convert.discount;
|
||||
|
||||
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.DiscountActivityCreateReqVO;
|
||||
import cn.iocoder.yudao.module.promotion.controller.admin.discount.vo.DiscountActivityRespVO;
|
||||
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 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;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
/**
|
||||
* TODO 占位
|
||||
*/
|
||||
package cn.iocoder.yudao.module.promotion.convert.discount;
|
|
@ -7,8 +7,6 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
|||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 限时折扣商品 DO
|
||||
*
|
||||
|
@ -31,12 +29,6 @@ public class DiscountProductDO extends BaseDO {
|
|||
* 关联 {@link DiscountActivityDO#getId()}
|
||||
*/
|
||||
private Long activityId;
|
||||
/**
|
||||
* 限时折扣活动的名字
|
||||
*
|
||||
* 冗余 {@link DiscountActivityDO#getName()}
|
||||
*/
|
||||
private String activityName;
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*
|
||||
|
@ -49,23 +41,9 @@ public class DiscountProductDO extends BaseDO {
|
|||
* 关联 ProductSkuDO 的 id 编号
|
||||
*/
|
||||
private Long skuId;
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private Date startTime;
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private Date endTime;
|
||||
/**
|
||||
* 销售价格,单位:分
|
||||
*
|
||||
* 冗余 ProductSkuDO 的 price 字段
|
||||
*/
|
||||
private Integer originalPrice;
|
||||
/**
|
||||
* 优惠价格,单位:分
|
||||
*/
|
||||
private Integer promotionPrice;
|
||||
private Integer discountPrice;
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
/**
|
||||
* TODO 占位
|
||||
*/
|
||||
package cn.iocoder.yudao.module.promotion.dal.mysql.discount;
|
|
@ -7,6 +7,9 @@ import cn.iocoder.yudao.module.promotion.controller.admin.reward.vo.RewardActivi
|
|||
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
|
||||
*
|
||||
|
@ -22,4 +25,8 @@ public interface RewardActivityMapper extends BaseMapperX<RewardActivityDO> {
|
|||
.orderByDesc(RewardActivityDO::getId));
|
||||
}
|
||||
|
||||
default List<RewardActivityDO> selectListByStatus(Collection<Integer> statuses) {
|
||||
return selectList(RewardActivityDO::getStatus, statuses);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
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 javax.validation.Valid;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 限时折扣 Service 接口
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public interface DiscountActivityService {
|
||||
|
||||
/**
|
||||
* 基于指定 SKU 编号数组,获得匹配的限时折扣商品
|
||||
*
|
||||
* 注意,匹配的条件,仅仅是日期符合,并且处于开启状态
|
||||
*
|
||||
* @param skuIds SKU 编号数组
|
||||
* @return 匹配的限时折扣商品
|
||||
*/
|
||||
Map<Long, DiscountProductDO> 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);
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package cn.iocoder.yudao.module.promotion.service.discount;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
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.convertSet;
|
||||
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;
|
||||
|
||||
// TODO 芋艿:待实现
|
||||
@Override
|
||||
public Map<Long, DiscountProductDO> getMatchDiscountProducts(Collection<Long> skuIds) {
|
||||
Map<Long, DiscountProductDO> products = new HashMap<>();
|
||||
products.put(1L, new DiscountProductDO().setDiscountPrice(100));
|
||||
products.put(2L, new DiscountProductDO().setDiscountPrice(50));
|
||||
return products;
|
||||
}
|
||||
|
||||
@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);
|
||||
// 返回
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验商品是否冲突
|
||||
*
|
||||
* @param id 编号
|
||||
* @param products 商品列表
|
||||
*/
|
||||
private void validateDiscountActivityProductConflicts(Long id, List<DiscountActivityBaseVO.Product> products) {
|
||||
if (CollUtil.isEmpty(products)) {
|
||||
return;
|
||||
}
|
||||
// 查询商品参加的活动
|
||||
List<DiscountProductDetailBO> discountActivityProductList = getRewardActivityListBySkuIds(
|
||||
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> getRewardActivityListBySkuIds(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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
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 discountPrice;
|
||||
|
||||
// ========== DiscountActivityDO 字段 ==========
|
||||
/**
|
||||
* 活动标题
|
||||
*/
|
||||
private String activityName;
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProduct
|
|||
import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.*;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
|
||||
import cn.iocoder.yudao.module.promotion.service.discount.DiscountService;
|
||||
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
|
||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
|
||||
|
@ -54,7 +54,7 @@ import static java.util.Collections.singletonList;
|
|||
public class PriceServiceImpl implements PriceService {
|
||||
|
||||
@Resource
|
||||
private DiscountService discountService;
|
||||
private DiscountActivityService discountService;
|
||||
@Resource
|
||||
private RewardActivityService rewardActivityService;
|
||||
@Resource
|
||||
|
@ -121,7 +121,7 @@ public class PriceServiceImpl implements PriceService {
|
|||
Double memberDiscountPercent = memberDiscountPercentSupplier.get();
|
||||
DiscountProductDO discountProduct = discountProducts.get(orderItem.getSkuId());
|
||||
if (discountProduct != null // 假设优惠价格更贵,则认为没优惠
|
||||
&& discountProduct.getPromotionPrice() >= orderItem.getOriginalUnitPrice()) {
|
||||
&& discountProduct.getDiscountPrice() >= orderItem.getOriginalUnitPrice()) {
|
||||
discountProduct = null;
|
||||
}
|
||||
if (memberDiscountPercent == null && discountProduct == null) {
|
||||
|
@ -129,7 +129,7 @@ public class PriceServiceImpl implements PriceService {
|
|||
}
|
||||
// 计算价格,判断选择哪个折扣
|
||||
Integer memberPrice = memberDiscountPercent != null ? (int) (orderItem.getPayPrice() * memberDiscountPercent / 100) : null;
|
||||
Integer promotionPrice = discountProduct != null ? discountProduct.getPromotionPrice() * orderItem.getCount() : null;
|
||||
Integer promotionPrice = discountProduct != null ? discountProduct.getDiscountPrice() * orderItem.getCount() : null;
|
||||
if (memberPrice == null) {
|
||||
calculatePriceByDiscountActivity(priceCalculate, orderItem, discountProduct, promotionPrice);
|
||||
} else if (promotionPrice == null) {
|
||||
|
@ -155,7 +155,8 @@ public class PriceServiceImpl implements PriceService {
|
|||
private void calculatePriceByDiscountActivity(PriceCalculateRespDTO priceCalculate, PriceCalculateRespDTO.OrderItem orderItem,
|
||||
DiscountProductDO discountProduct, Integer promotionPrice) {
|
||||
// 记录优惠明细
|
||||
addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), discountProduct.getActivityName(),
|
||||
addPromotion(priceCalculate, orderItem, discountProduct.getActivityId(), null
|
||||
/* TODO 芋艿:修复下 discountProduct.getActivityName()*/,
|
||||
PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), PromotionLevelEnum.SKU.getLevel(), promotionPrice,
|
||||
true, StrUtil.format("限时折扣:省 {} 元", formatPrice(orderItem.getPayPrice() - promotionPrice)));
|
||||
// 修改 SKU 的优惠
|
||||
|
|
|
@ -14,13 +14,11 @@ 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 java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* 满减送活动 Service 实现类
|
||||
|
@ -54,6 +52,7 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
|||
if (dbRewardActivity.getStatus().equals(PromotionActivityStatusEnum.CLOSE.getStatus())) { // 已关闭的活动,不能修改噢
|
||||
throw exception(REWARD_ACTIVITY_UPDATE_FAIL_STATUS_CLOSED);
|
||||
}
|
||||
// 校验商品是否冲突
|
||||
validateRewardActivitySpuConflicts(updateReqVO.getId(), updateReqVO.getProductSpuIds());
|
||||
|
||||
// 更新
|
||||
|
@ -109,8 +108,9 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
|||
return;
|
||||
}
|
||||
// 查询商品参加的活动
|
||||
List<RewardActivityDO> rewardActivityList = getRewardActivityListBySpuIds(spuIds);
|
||||
if (id != null) { // 排除活动
|
||||
List<RewardActivityDO> rewardActivityList = getRewardActivityListBySpuIds(spuIds,
|
||||
asList(PromotionActivityStatusEnum.WAIT.getStatus(), PromotionActivityStatusEnum.RUN.getStatus()));
|
||||
if (id != null) { // 排除自己这个活动
|
||||
rewardActivityList.removeIf(activity -> id.equals(activity.getId()));
|
||||
}
|
||||
// 如果非空,则说明冲突
|
||||
|
@ -123,10 +123,12 @@ public class RewardActivityServiceImpl implements RewardActivityService {
|
|||
* 获得商品参加的满减送活动的数组
|
||||
*
|
||||
* @param spuIds 商品 SPU 编号数组
|
||||
* @param statuses 活动状态数组
|
||||
* @return 商品参加的满减送活动的数组
|
||||
*/
|
||||
private List<RewardActivityDO> getRewardActivityListBySpuIds(Collection<Long> spuIds) {
|
||||
List<RewardActivityDO> list = rewardActivityMapper.selectList();
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
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.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.mysql.discount.DiscountActivityMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionActivityStatusEnum;
|
||||
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 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 org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* {@link DiscountActivityServiceImpl} 的单元测试类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Import(DiscountActivityServiceImpl.class)
|
||||
public class DiscountActivityServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private DiscountActivityServiceImpl discountActivityService;
|
||||
|
||||
@Resource
|
||||
private DiscountActivityMapper discountActivityMapper;
|
||||
|
||||
@Test
|
||||
public void testCreateDiscountActivity_success() {
|
||||
// 准备参数
|
||||
DiscountActivityCreateReqVO reqVO = randomPojo(DiscountActivityCreateReqVO.class, o -> {
|
||||
// 用于触发进行中的状态
|
||||
o.setStartTime(addTime(Duration.ofDays(1))).setEndTime(addTime(Duration.ofDays(2)));
|
||||
});
|
||||
|
||||
// 调用
|
||||
Long discountActivityId = discountActivityService.createDiscountActivity(reqVO);
|
||||
// 断言
|
||||
assertNotNull(discountActivityId);
|
||||
// 校验记录的属性是否正确
|
||||
DiscountActivityDO discountActivity = discountActivityMapper.selectById(discountActivityId);
|
||||
assertPojoEquals(reqVO, discountActivity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateDiscountActivity_success() {
|
||||
// mock 数据
|
||||
DiscountActivityDO dbDiscountActivity = randomPojo(DiscountActivityDO.class);
|
||||
discountActivityMapper.insert(dbDiscountActivity);// @Sql: 先插入出一条存在的数据
|
||||
// 准备参数
|
||||
DiscountActivityUpdateReqVO reqVO = randomPojo(DiscountActivityUpdateReqVO.class, o -> {
|
||||
o.setId(dbDiscountActivity.getId()); // 设置更新的 ID
|
||||
});
|
||||
|
||||
// 调用
|
||||
discountActivityService.updateDiscountActivity(reqVO);
|
||||
// 校验是否更新正确
|
||||
DiscountActivityDO discountActivity = discountActivityMapper.selectById(reqVO.getId()); // 获取最新的
|
||||
assertPojoEquals(reqVO, discountActivity);
|
||||
}
|
||||
|
||||
@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);
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
|
@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.discount.DiscountProduct
|
|||
import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.*;
|
||||
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
|
||||
import cn.iocoder.yudao.module.promotion.service.discount.DiscountService;
|
||||
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
|
||||
import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
|
@ -41,7 +41,7 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
|
|||
private PriceServiceImpl priceService;
|
||||
|
||||
@Mock
|
||||
private DiscountService discountService;
|
||||
private DiscountActivityService discountService;
|
||||
@Mock
|
||||
private RewardActivityService rewardActivityService;
|
||||
@Mock
|
||||
|
@ -109,10 +109,10 @@ public class PriceServiceTest extends BaseMockitoUnitTest {
|
|||
ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50));
|
||||
when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02));
|
||||
// mock 方法(限时折扣 DiscountActivity 信息)
|
||||
DiscountProductDO discountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(1000L).setActivityName("活动 1000 号")
|
||||
.setSkuId(10L).setPromotionPrice(80));
|
||||
DiscountProductDO discountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(2000L).setActivityName("活动 2000 号")
|
||||
.setSkuId(20L).setPromotionPrice(40));
|
||||
DiscountProductDO discountProduct01 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(1000L)/*.setActsivityName("活动 1000 号") TODO 芋艿:待完善 */
|
||||
.setSkuId(10L).setDiscountPrice(80));
|
||||
DiscountProductDO discountProduct02 = randomPojo(DiscountProductDO.class, o -> o.setActivityId(2000L)/*.setActivityName("活动 2000 号") TODO 芋艿:待完善 */
|
||||
.setSkuId(20L).setDiscountPrice(80));
|
||||
when(discountService.getMatchDiscountProducts(eq(asSet(10L, 20L)))).thenReturn(
|
||||
MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map());
|
||||
|
||||
|
|
|
@ -2,3 +2,5 @@ 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";
|
||||
|
|
|
@ -91,3 +91,32 @@ CREATE TABLE IF NOT EXISTS "promotion_reward_activity" (
|
|||
"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_price" int NOT NULL,
|
||||
"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 '限时折扣活动';
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 创建限时折扣活动
|
||||
export function createDiscountActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 更新限时折扣活动
|
||||
export function updateDiscountActivity(data) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 关闭限时折扣活动
|
||||
export function closeDiscountActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/close?id=' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除限时折扣活动
|
||||
export function deleteDiscountActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/delete?id=' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得限时折扣活动
|
||||
export function getDiscountActivity(id) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/get?id=' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得限时折扣活动分页
|
||||
export function getDiscountActivityPage(query) {
|
||||
return request({
|
||||
url: '/promotion/discount-activity/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
|
||||
<!-- 搜索工作栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="活动名称" prop="name">
|
||||
<el-input v-model="queryParams.name" placeholder="请输入活动名称" clearable @keyup.enter.native="handleQuery"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="活动状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择活动状态" clearable size="small">
|
||||
<el-option v-for="dict in this.getDictDatas(DICT_TYPE.PROMOTION_ACTIVITY_STATUS)"
|
||||
:key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间" prop="createTime">
|
||||
<el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
|
||||
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作工具栏 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
|
||||
v-hasPermi="['promotion:discount-activity:create']">新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table v-loading="loading" :data="list">
|
||||
<el-table-column label="活动名称" align="center" prop="name" />
|
||||
<el-table-column label="活动时间" align="center" prop="startTime" width="240">
|
||||
<template slot-scope="scope">
|
||||
<div>开始:{{ parseTime(scope.row.startTime) }}</div>
|
||||
<div>结束:{{ parseTime(scope.row.endTime) }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :type="DICT_TYPE.PROMOTION_ACTIVITY_STATUS" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
|
||||
v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type"
|
||||
v-hasPermi="['promotion:discount-activity:update']">修改</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleClose(scope.row)"
|
||||
v-if="scope.row.status !== PromotionActivityStatusEnum.CLOSE.type &&
|
||||
scope.row.status !== PromotionActivityStatusEnum.END.type"
|
||||
v-hasPermi="['promotion:discount-activity:close']">关闭</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||
v-if="scope.row.status === PromotionActivityStatusEnum.CLOSE.type"
|
||||
v-hasPermi="['promotion:discount-activity:delete']">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 分页组件 -->
|
||||
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"/>
|
||||
|
||||
<!-- 对话框(添加 / 修改) -->
|
||||
<el-dialog :title="title" :visible.sync="open" width="600px" v-dialogDrag append-to-body>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="活动名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入活动名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
<el-form-item label="活动时间" prop="startAndEndTime">
|
||||
<el-date-picker clearable v-model="form.startAndEndTime" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
|
||||
value-format="timestamp" placeholder="选择开始时间" style="width: 480px" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createDiscountActivity, updateDiscountActivity, deleteDiscountActivity, getDiscountActivity, getDiscountActivityPage } from "@/api/mall/promotion/discountActivity";
|
||||
import {PromotionActivityStatusEnum, PromotionProductScopeEnum} from "@/utils/constants";
|
||||
import {closeRewardActivity} from "@/api/mall/promotion/rewardActivity";
|
||||
|
||||
export default {
|
||||
name: "DiscountActivity",
|
||||
components: {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 导出遮罩层
|
||||
exportLoading: false,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 限时折扣活动列表
|
||||
list: [],
|
||||
// 弹出层名称
|
||||
title: "",
|
||||
// 是否显示弹出层
|
||||
open: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: null,
|
||||
status: null,
|
||||
createTime: [],
|
||||
},
|
||||
// 表单参数
|
||||
form: {},
|
||||
// 表单校验
|
||||
rules: {
|
||||
name: [{ required: true, message: "活动名称不能为空", trigger: "blur" }],
|
||||
startAndEndTime: [{ required: true, message: "活动时间不能为空", trigger: "blur" }],
|
||||
},
|
||||
// 商品列表
|
||||
productSpus: [], // TODO 芋艿:需要重新写下
|
||||
// 如下的变量,主要为了 v-if 判断可以使用到
|
||||
PromotionProductScopeEnum: PromotionProductScopeEnum,
|
||||
PromotionActivityStatusEnum: PromotionActivityStatusEnum,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
// 执行查询
|
||||
getDiscountActivityPage(this.queryParams).then(response => {
|
||||
this.list = response.data.list;
|
||||
this.total = response.data.total;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
startAndEndTime: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
remark: undefined,
|
||||
};
|
||||
this.resetForm("form");
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNo = 1;
|
||||
this.getList();
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm");
|
||||
this.handleQuery();
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加限时折扣活动";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.reset();
|
||||
const id = row.id;
|
||||
getDiscountActivity(id).then(response => {
|
||||
this.form = response.data;
|
||||
this.form.startAndEndTime = [response.data.startTime, response.data.endTime];
|
||||
this.open = true;
|
||||
this.title = "修改限时折扣活动";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
this.form.startTime = this.form.startAndEndTime[0];
|
||||
this.form.endTime = this.form.startAndEndTime[1];
|
||||
// 修改的提交
|
||||
if (this.form.id != null) {
|
||||
updateDiscountActivity(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 添加的提交
|
||||
createDiscountActivity(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
});
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const id = row.id;
|
||||
this.$modal.confirm('是否确认删除限时折扣活动编号为"' + id + '"的数据项?').then(function() {
|
||||
return deleteDiscountActivity(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("删除成功");
|
||||
}).catch(() => {});
|
||||
},
|
||||
/** 关闭按钮操作 */
|
||||
handleClose(row) {
|
||||
const id = row.id;
|
||||
this.$modal.confirm('是否确认关闭限时折扣活动编号为"' + id + '"的数据项?').then(function() {
|
||||
return closeRewardActivity(id);
|
||||
}).then(() => {
|
||||
this.getList();
|
||||
this.$modal.msgSuccess("关闭成功");
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
Loading…
Reference in New Issue