fix: 完善拼团、秒杀、砍价活动管理

This commit is contained in:
puhui999 2023-08-06 17:46:16 +08:00
parent afaef0dfbb
commit 5f9184904a
32 changed files with 1284 additions and 247 deletions

View File

@ -2,7 +2,6 @@ package cn.iocoder.yudao.framework.common.util.collection;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.google.common.collect.ImmutableMap;
import java.util.*;
@ -26,8 +25,7 @@ public class CollectionUtils {
return Arrays.stream(collections).anyMatch(CollectionUtil::isEmpty);
}
// TODO @puhui999anyMatch 更统一点
public static <T> boolean isAny(Collection<T> from, Predicate<T> predicate) {
public static <T> boolean anyMatch(Collection<T> from, Predicate<T> predicate) {
return from.stream().anyMatch(predicate);
}
@ -154,41 +152,6 @@ public class CollectionUtils {
return builder.build();
}
/**
* 数据划分为需要新增的还是删除的还是更新的
*
* @param list1 需要处理的数据的相关编号列表
* @param list2 数据库中存在的数据的相关编号列表
* @param func 比较出哪些记录是新增还是修改还是删除
* @return 包含需要新增修改删除的数据 Map 对象
*/
public static <D> Map<String, List<D>> convertCDUMap(Collection<Long> list1, Collection<Long> list2,
Function<Map<String, List<Long>>, Map<String, List<D>>> func) {
HashMap<String, List<Long>> mapData = MapUtil.newHashMap(3);
if (CollUtil.isEmpty(list1)) {
return func.apply(mapData);
}
if (CollUtil.isEmpty(list2)) {
return func.apply(mapData);
}
// 后台存在的前端不存在的
List<Long> d = CollectionUtils.filterList(list2, item -> !list1.contains(item));
if (CollUtil.isNotEmpty(d)) {
mapData.put("delete", d);
}
// 前端存在的后端不存在的
List<Long> c = CollectionUtils.filterList(list1, item -> !list2.contains(item));
if (CollUtil.isNotEmpty(c)) {
mapData.put("create", c);
}
// 更新已存在的
List<Long> u = CollectionUtils.filterList(list1, list2::contains);
if (CollUtil.isNotEmpty(u)) {
mapData.put("update", u);
}
return func.apply(mapData);
}
/**
* 对比老新两个列表找出新增修改删除的数据
*

View File

@ -69,4 +69,14 @@ public interface ErrorCodeConstants {
ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013010006, "拼团失败,父拼团不存在");
ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013010006, "拼团失败,拼团人数已满");
// ========== 砍价活动 1013011000 ==========
ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1013011000, "砍价活动不存在");
ErrorCode BARGAIN_ACTIVITY_SPU_CONFLICTS = new ErrorCode(1013011001, "存在商品参加了其它砍价活动");
ErrorCode BARGAIN_ACTIVITY_STATUS_DISABLE = new ErrorCode(1013011002, "砍价活动已关闭不能修改");
ErrorCode BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013011003, "砍价活动未关闭或未结束,不能删除");
ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013011004, "砍价不存在");
ErrorCode BARGAIN_RECORD_EXISTS = new ErrorCode(1013011005, "砍价失败,已参与过该砍价");
ErrorCode BARGAIN_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013011006, "砍价失败,父砍价不存在");
ErrorCode BARGAIN_RECORD_USER_FULL = new ErrorCode(1013011007, "砍价失败,砍价人数已满");
}

View File

@ -0,0 +1,91 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainProductDO;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
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 java.util.Set;
import static cn.hutool.core.collection.CollectionUtil.newArrayList;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@Tag(name = "管理后台 - 砍价活动")
@RestController
@RequestMapping("/promotion/bargain-activity")
@Validated
public class BargainActivityController {
@Resource
private BargainActivityService activityService;
@Resource
private ProductSpuApi spuApi;
@PostMapping("/create")
@Operation(summary = "创建砍价活动")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:create')")
public CommonResult<Long> createBargainActivity(@Valid @RequestBody BargainActivityCreateReqVO createReqVO) {
return success(activityService.createBargainActivity(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新砍价活动")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:update')")
public CommonResult<Boolean> updateBargainActivity(@Valid @RequestBody BargainActivityUpdateReqVO updateReqVO) {
activityService.updateBargainActivity(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除砍价活动")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:delete')")
public CommonResult<Boolean> deleteBargainActivity(@RequestParam("id") Long id) {
activityService.deleteBargainActivity(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得砍价活动")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')")
public CommonResult<BargainActivityRespVO> getBargainActivity(@RequestParam("id") Long id) {
BargainActivityDO activity = activityService.getBargainActivity(id);
List<BargainProductDO> products = activityService.getBargainProductsByActivityIds(newArrayList(id));
return success(BargainActivityConvert.INSTANCE.convert(activity, products));
}
@GetMapping("/page")
@Operation(summary = "获得砍价活动分页")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:query')")
public CommonResult<PageResult<BargainActivityRespVO>> getBargainActivityPage(
@Valid BargainActivityPageReqVO pageVO) {
// 查询砍价活动
PageResult<BargainActivityDO> pageResult = activityService.getBargainActivityPage(pageVO);
// 拼接数据
Set<Long> activityIds = convertSet(pageResult.getList(), BargainActivityDO::getId);
Set<Long> spuIds = convertSet(pageResult.getList(), BargainActivityDO::getSpuId);
return success(BargainActivityConvert.INSTANCE.convertPage(pageResult,
activityService.getBargainProductsByActivityIds(activityIds),
spuApi.getSpuList(spuIds)));
}
}

View File

@ -0,0 +1,59 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
/**
* 砍价活动 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*
* @author HUIHUI
*/
@Data
public class BargainActivityBaseVO {
@Schema(description = "砍价活动名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "越拼越省钱")
@NotNull(message = "砍价名称不能为空")
private String name;
@Schema(description = "商品 SPU 编号,关联 ProductSpuDO 的 id", example = "[1,2,3]")
@NotNull(message = "砍价商品不能为空")
private Long spuId;
@Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218")
@NotNull(message = "总限购数量不能为空")
private Integer totalLimitCount;
@Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@NotNull(message = "活动开始时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime startTime;
@Schema(description = "活动结束时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@NotNull(message = "活动结束时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
@Schema(description = "砍价人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "砍价人数不能为空")
private Integer userSize;
@Schema(description = "最大帮砍次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "最大帮砍次数不能为空")
private Integer bargainCount;
@Schema(description = "用户每次砍价的最小金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "用户每次砍价的最小金额不能为空")
private Integer randomMinPrice;
@Schema(description = "用户每次砍价的最大金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "用户每次砍价的最大金额不能为空")
private Integer randomMaxPrice;
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductCreateReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.Valid;
import java.util.List;
@Schema(description = "管理后台 - 砍价活动创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityCreateReqVO extends BargainActivityBaseVO {
@Schema(description = "砍价商品", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid
private List<BargainProductCreateReqVO> products;
}

View File

@ -0,0 +1,65 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 砍价活动分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityPageReqVO extends PageParam {
@Schema(description = "砍价名称", example = "赵六")
private String name;
@Schema(description = "商品 SPU 编号关联 ProductSpuDO 的 id", example = "14016")
private Long spuId;
@Schema(description = "总限购数量", example = "16218")
private Integer totalLimitCount;
@Schema(description = "单次限购数量", example = "28265")
private Integer singleLimitCount;
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] startTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] endTime;
@Schema(description = "开团人数")
private Integer userSize;
@Schema(description = "开团组数")
private Integer totalNum;
@Schema(description = "成团组数")
private Integer successNum;
@Schema(description = "参与人数", example = "25222")
private Integer orderUserCount;
@Schema(description = "虚拟成团")
private Integer virtualGroup;
@Schema(description = "活动状态0开启 1关闭", example = "0")
private Integer status;
@Schema(description = "限制时长(小时)")
private Integer limitDuration;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 砍价活动 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityRespVO extends BargainActivityBaseVO {
@Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "618大促")
private String spuName;
@Schema(description = "商品主图", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xx.png")
private String picUrl;
@Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
@Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开团人数不能为空")
private Integer userSize;
@Schema(description = "开团组数", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "开团组数不能为空")
private Integer totalNum;
@Schema(description = "成团组数", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "成团组数不能为空")
private Integer successNum;
@Schema(description = "虚拟成团", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "虚拟成团不能为空")
private Integer virtualGroup;
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "活动状态不能为空")
private Integer status;
@Schema(description = "砍价商品", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid
private List<BargainProductRespVO> products;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductUpdateReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
@Schema(description = "管理后台 - 砍价活动更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainActivityUpdateReqVO extends BargainActivityBaseVO {
@Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
@NotNull(message = "活动编号不能为空")
private Long id;
@Schema(description = "砍价商品", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid
private List<BargainProductUpdateReqVO> products;
}

View File

@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 砍价商品 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*/
@Data
public class BargainProductBaseVO {
@Schema(description = "商品 spuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
@NotNull(message = "商品 spuId 不能为空")
private Long spuId;
@Schema(description = "商品 skuId", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "商品 skuId 不能为空")
private Long skuId;
@Schema(description = "砍价起始价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "砍价起始价格不能为空")
private Integer bargainFirstPrice;
@Schema(description = "砍价底价", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "砍价底价不能为空")
private Integer bargainPrice;
@Schema(description = "活动库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "23")
@NotNull(message = "活动库存不能为空")
private Integer stock;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 砍价商品创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainProductCreateReqVO extends BargainProductBaseVO {
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 砍价商品分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainProductPageReqVO extends PageParam {
@Schema(description = "砍价活动编号", example = "6829")
private Long activityId;
@Schema(description = "商品 SPU 编号", example = "18731")
private Long spuId;
@Schema(description = "商品 SKU 编号", example = "31675")
private Long skuId;
@Schema(description = "砍价商品状态", example = "2")
private Integer activityStatus;
@Schema(description = "活动开始时间点")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] activityStartTime;
@Schema(description = "活动结束时间点")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] activityEndTime;
@Schema(description = "砍价价格,单位分", example = "27682")
private Integer activePrice;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 砍价商品 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainProductRespVO extends BargainProductBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28322")
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Schema(description = "管理后台 - 砍价商品更新 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class BargainProductUpdateReqVO extends BargainProductBaseVO {
}

View File

@ -20,7 +20,6 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@ -74,16 +73,6 @@ public class CombinationActivityController {
return success(CombinationActivityConvert.INSTANCE.convert(activity, products));
}
// TODO @puhui999是不是可以删掉貌似没用
@GetMapping("/list")
@Operation(summary = "获得拼团活动列表")
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")
public CommonResult<List<CombinationActivityRespVO>> getCombinationActivityList(@RequestParam("ids") Collection<Long> ids) {
List<CombinationActivityDO> list = combinationActivityService.getCombinationActivityList(ids);
return success(CombinationActivityConvert.INSTANCE.convertList(list));
}
@GetMapping("/page")
@Operation(summary = "获得拼团活动分页")
@PreAuthorize("@ss.hasPermission('promotion:combination-activity:query')")

View File

@ -12,6 +12,8 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
/**
* 拼团活动 Base VO提供给添加修改详细的子 VO 使用
* 如果子 VO 存在差异的字段请不要添加到这里影响 Swagger 文档生成
*
* @author HUIHUI
*/
@Data
public class CombinationActivityBaseVO {
@ -32,11 +34,15 @@ public class CombinationActivityBaseVO {
@NotNull(message = "单次限购数量不能为空")
private Integer singleLimitCount;
// TODO @puhui999是不是弄成 2 个字段会好点哈开始结束
@Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 00:00:00,2022-07-01 23:59:59]")
@Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@NotNull(message = "活动时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] activityTime;
private LocalDateTime startTime;
@Schema(description = "活动时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "[2022-07-01 23:59:59]")
@NotNull(message = "活动时间不能为空")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime endTime;
@Schema(description = "开团人数", requiredMode = Schema.RequiredMode.REQUIRED, example = "25222")
@NotNull(message = "开团人数不能为空")

View File

@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.promotion.controller.admin.seckill;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*;
@ -19,11 +18,11 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
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;
@Tag(name = "管理后台 - 秒杀活动")
@RestController
@ -79,24 +78,14 @@ public class SeckillActivityController {
return success(SeckillActivityConvert.INSTANCE.convert(seckillActivity, seckillProducts));
}
// TODO @puhui999是不是可以删掉貌似没用
@GetMapping("/list")
@Operation(summary = "获得秒杀活动列表")
@Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
public CommonResult<List<SeckillActivityRespVO>> getSeckillActivityList(@RequestParam("ids") Collection<Long> ids) {
List<SeckillActivityDO> list = seckillActivityService.getSeckillActivityList(ids);
return success(SeckillActivityConvert.INSTANCE.complementList(list));
}
@GetMapping("/page")
@Operation(summary = "获得秒杀活动分页")
@PreAuthorize("@ss.hasPermission('promotion:seckill-activity:query')")
public CommonResult<PageResult<SeckillActivityRespVO>> getSeckillActivityPage(@Valid SeckillActivityPageReqVO pageVO) {
PageResult<SeckillActivityDO> pageResult = seckillActivityService.getSeckillActivityPage(pageVO);
Set<Long> aIds = CollectionUtils.convertSet(pageResult.getList(), SeckillActivityDO::getId);
Set<Long> aIds = convertSet(pageResult.getList(), SeckillActivityDO::getId);
List<SeckillProductDO> seckillProducts = seckillActivityService.getSeckillProductListByActivityId(aIds);
Set<Long> spuIds = CollectionUtils.convertSet(pageResult.getList(), SeckillActivityDO::getSpuId);
Set<Long> spuIds = convertSet(pageResult.getList(), SeckillActivityDO::getSpuId);
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(spuIds);
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, seckillProducts, spuList));
}

View File

@ -0,0 +1,95 @@
package cn.iocoder.yudao.module.promotion.convert.bargain;
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.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainProductDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/**
* 拼团活动 Convert
*
* @author HUIHUI
*/
@Mapper
public interface BargainActivityConvert {
BargainActivityConvert INSTANCE = Mappers.getMapper(BargainActivityConvert.class);
BargainActivityDO convert(BargainActivityCreateReqVO bean);
BargainActivityDO convert(BargainActivityUpdateReqVO bean);
BargainActivityRespVO convert(BargainActivityDO bean);
BargainProductRespVO convert(BargainProductDO bean);
default BargainActivityRespVO convert(BargainActivityDO bean, List<BargainProductDO> productDOs) {
return convert(bean).setProducts(convertList2(productDOs));
}
List<BargainActivityRespVO> convertList(List<BargainActivityDO> list);
PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page);
default PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page,
List<BargainProductDO> productList,
List<ProductSpuRespDTO> spuList) {
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
PageResult<BargainActivityRespVO> pageResult = convertPage(page);
pageResult.getList().forEach(item -> {
MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> {
item.setSpuName(spu.getName());
item.setPicUrl(spu.getPicUrl());
});
item.setProducts(convertList2(productList));
});
return pageResult;
}
List<BargainProductRespVO> convertList2(List<BargainProductDO> productDOs);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(target = "activityId", source = "activityDO.id"),
@Mapping(target = "spuId", source = "activityDO.spuId"),
@Mapping(target = "skuId", source = "vo.skuId"),
@Mapping(target = "bargainFirstPrice", source = "vo.bargainFirstPrice"),
@Mapping(target = "bargainPrice", source = "vo.bargainPrice"),
@Mapping(target = "stock", source = "vo.stock"),
@Mapping(target = "activityStartTime", source = "activityDO.startTime"),
@Mapping(target = "activityEndTime", source = "activityDO.endTime")
})
BargainProductDO convert(BargainActivityDO activityDO, BargainProductBaseVO vo);
default List<BargainProductDO> convertList(List<? extends BargainProductBaseVO> products, BargainActivityDO activityDO) {
return CollectionUtils.convertList(products, item -> convert(activityDO, item).setActivityStatus(activityDO.getStatus()));
}
default List<BargainProductDO> convertList(List<BargainProductUpdateReqVO> updateProductVOs,
List<BargainProductDO> products, BargainActivityDO activity) {
Map<Long, Long> productMap = convertMap(products, BargainProductDO::getSkuId, BargainProductDO::getId);
return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
.setId(productMap.get(updateProductVO.getSkuId()))
.setActivityStatus(activity.getStatus()));
}
//BargainRecordDO convert(BargainRecordCreateReqDTO reqDTO);
}

View File

@ -17,11 +17,8 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -37,38 +34,16 @@ public interface CombinationActivityConvert {
CombinationActivityConvert INSTANCE = Mappers.getMapper(CombinationActivityConvert.class);
@Mappings({
@Mapping(target = "startTime", expression = "java(bean.getActivityTime()[0])"),
@Mapping(target = "endTime", expression = "java(bean.getActivityTime()[1])")
})
CombinationActivityDO convert(CombinationActivityCreateReqVO bean);
@Mappings({
@Mapping(target = "startTime", expression = "java(bean.getActivityTime()[0])"),
@Mapping(target = "endTime", expression = "java(bean.getActivityTime()[1])")
})
CombinationActivityDO convert(CombinationActivityUpdateReqVO bean);
@Named("mergeTime")
default LocalDateTime[] mergeTime(LocalDateTime startTime, LocalDateTime endTime) {
// TODO 有点怪第一次这样写 hh
LocalDateTime[] localDateTime = new LocalDateTime[2];
localDateTime[0] = startTime;
localDateTime[1] = endTime;
return localDateTime;
}
@Mappings({
@Mapping(target = "activityTime", expression = "java(mergeTime(bean.getStartTime(),bean.getEndTime()))")
})
CombinationActivityRespVO convert(CombinationActivityDO bean);
CombinationProductRespVO convert(CombinationProductDO bean);
default CombinationActivityRespVO convert(CombinationActivityDO bean, List<CombinationProductDO> productDOs) {
CombinationActivityRespVO respVO = convert(bean);
respVO.setProducts(convertList2(productDOs));
return respVO;
return convert(bean).setProducts(convertList2(productDOs));
}
List<CombinationActivityRespVO> convertList(List<CombinationActivityDO> list);
@ -104,21 +79,15 @@ public interface CombinationActivityConvert {
CombinationProductDO convert(CombinationActivityDO activityDO, CombinationProductBaseVO vo);
default List<CombinationProductDO> convertList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activityDO) {
List<CombinationProductDO> list = new ArrayList<>();
products.forEach(sku -> {
CombinationProductDO productDO = convert(activityDO, sku);
productDO.setActivityStatus(activityDO.getStatus());
list.add(productDO);
});
return list;
return CollectionUtils.convertList(products, item -> convert(activityDO, item).setActivityStatus(activityDO.getStatus()));
}
default List<CombinationProductDO> convertList(List<CombinationProductUpdateReqVO> updateProductVOs,
List<CombinationProductDO> products, CombinationActivityDO activity) {
Map<Long, Long> productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId);
return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
.setId(productMap.get(updateProductVO.getSkuId()))
.setActivityStatus(activity.getStatus()));
.setId(productMap.get(updateProductVO.getSkuId()))
.setActivityStatus(activity.getStatus()));
}
CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);

View File

@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
import org.mapstruct.Mapper;
@ -17,12 +16,9 @@ import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
/**
* 秒杀活动 Convert
*
@ -39,8 +35,7 @@ public interface SeckillActivityConvert {
SeckillActivityRespVO convert(SeckillActivityDO bean);
// TODO @puhui999这个是不是还是 convertList 好点
List<SeckillActivityRespVO> complementList(List<SeckillActivityDO> list);
List<SeckillActivityRespVO> convertList(List<SeckillActivityDO> list);
PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
@ -58,9 +53,7 @@ public interface SeckillActivityConvert {
SeckillActivityDetailRespVO convert1(SeckillActivityDO seckillActivity);
default SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts) {
SeckillActivityDetailRespVO respVO = convert1(seckillActivity);
respVO.setProducts(convertList2(seckillProducts));
return respVO;
return convert1(seckillActivity).setProducts(convertList2(seckillProducts));
}
@Mappings({
@ -77,21 +70,7 @@ public interface SeckillActivityConvert {
SeckillProductDO convert(SeckillActivityDO activityDO, SeckillProductBaseVO vo);
default List<SeckillProductDO> convertList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activityDO) {
List<SeckillProductDO> list = new ArrayList<>();
products.forEach(sku -> {
SeckillProductDO productDO = convert(activityDO, sku);
productDO.setActivityStatus(activityDO.getStatus());
list.add(productDO);
});
return list;
}
default List<SeckillProductDO> convertList(List<SeckillProductUpdateReqVO> updateProductVOs,
List<SeckillProductDO> products, SeckillActivityDO activity) {
Map<Long, Long> productMap = convertMap(products, SeckillProductDO::getSkuId, SeckillProductDO::getId);
return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)
.setId(productMap.get(updateProductVO.getSkuId()))
.setActivityStatus(activity.getStatus()));
return CollectionUtils.convertList(products, item -> convert(activityDO, item).setActivityStatus(activityDO.getStatus()));
}
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> productDOs);

View File

@ -54,21 +54,6 @@ public class BargainActivityDO extends BaseDO {
*/
private Long spuId;
/**
* 商品 SKU 编号
*/
private Long skuId;
/**
* 应付金额单位分
*/
private Integer bargainFirstPrice;
/**
* 砍价底价单位
*/
private Integer bargainPrice;
/**
* 达到该人数才能砍到低价
*/
@ -79,6 +64,11 @@ public class BargainActivityDO extends BaseDO {
*/
private Integer bargainCount;
/**
* 总限购数量
*/
private Integer totalLimitCount;
/**
* 砍价库存
*/

View File

@ -0,0 +1,70 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
/**
* 砍价商品 DO
*
* @author HUIHUI
*/
@TableName("promotion_bargain_product")
@KeySequence("promotion_bargain_product_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BargainProductDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 砍价活动编号
*/
private Long activityId;
/**
* 商品 SPU 编号
*/
private Long spuId;
/**
* 商品 SKU 编号
*/
private Long skuId;
/**
* 砍价商品状态
*
* 关联 {@link BargainActivityDO#getStatus()}
*/
private Integer activityStatus;
/**
* 活动开始时间点
*/
private LocalDateTime activityStartTime;
/**
* 活动结束时间点
*/
private LocalDateTime activityEndTime;
/**
* 砍价起始价格单位分
*/
private Integer bargainFirstPrice;
/**
* 砍价底价单位
*/
private Integer bargainPrice;
/**
* 活动库存
*/
private Integer stock;
}

View File

@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
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.bargain.vo.activity.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 砍价活动 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
default PageResult<BargainActivityDO> selectPage(BargainActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BargainActivityDO>()
.likeIfPresent(BargainActivityDO::getName, reqVO.getName())
.orderByDesc(BargainActivityDO::getId));
}
default List<BargainActivityDO> selectListByStatus(Integer status) {
return selectList(BargainActivityDO::getStatus, status);
}
}

View File

@ -0,0 +1,37 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
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.bargain.vo.product.BargainProductPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainProductDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
/**
* 砍价商品 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface BargainProductMapper extends BaseMapperX<BargainProductDO> {
default PageResult<BargainProductDO> selectPage(BargainProductPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BargainProductDO>()
.eqIfPresent(BargainProductDO::getActivityId, reqVO.getActivityId())
.eqIfPresent(BargainProductDO::getSpuId, reqVO.getSpuId())
.eqIfPresent(BargainProductDO::getSkuId, reqVO.getSkuId())
.eqIfPresent(BargainProductDO::getActivityStatus, reqVO.getActivityStatus())
.betweenIfPresent(BargainProductDO::getActivityStartTime, reqVO.getActivityStartTime())
.betweenIfPresent(BargainProductDO::getActivityEndTime, reqVO.getActivityEndTime())
.betweenIfPresent(BargainProductDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(BargainProductDO::getId));
}
default List<BargainProductDO> selectListByActivityIds(Collection<Long> ids) {
return selectList(BargainProductDO::getActivityId, ids);
}
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 砍价记录 Mapper
*
* @author HUIHUI
*/
@Mapper
public interface BargainRecordMapper extends BaseMapperX<BargainRecordDO> {
// TODO @puhui999selectByUserIdAndOrderId
default BargainRecordDO selectRecord(Long userId, Long orderId) {
return selectOne(BargainRecordDO::getUserId, userId,
BargainRecordDO::getOrderId, orderId);
}
/**
* 查询砍价记录
*
* @param headId 团长编号
* @param activityId 活动编号
* @return 砍价记录
*/
default BargainRecordDO selectRecordByHeadId(Long headId, Long activityId, Integer status) {
return selectOne(new LambdaQueryWrapperX<BargainRecordDO>()
.eq(BargainRecordDO::getUserId, headId)
.eq(BargainRecordDO::getActivityId, activityId)
.eq(BargainRecordDO::getStatus, status));
}
default List<BargainRecordDO> selectListByHeadIdAndStatus(Long headId, Integer status) {
return selectList(new LambdaQueryWrapperX<BargainRecordDO>()
//.eq(BargainRecordDO::getHeadId, headId)
.eq(BargainRecordDO::getStatus, status));
}
default List<BargainRecordDO> selectListByStatus(Integer status) {
return selectList(BargainRecordDO::getStatus, status);
}
}

View File

@ -29,9 +29,10 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
* @return 拼团记录
*/
default CombinationRecordDO selectRecordByHeadId(Long headId, Long activityId, Integer status) {
return selectOne(CombinationRecordDO::getHeadId, headId,
CombinationRecordDO::getActivityId, activityId,
CombinationRecordDO::getStatus, status);
return selectOne(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getUserId, headId)
.eq(CombinationRecordDO::getActivityId, activityId)
.eq(CombinationRecordDO::getStatus, status));
}
default List<CombinationRecordDO> selectListByHeadIdAndStatus(Long headId, Integer status) {

View File

@ -0,0 +1,75 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainProductDO;
import javax.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
* 砍价活动 Service 接口
*
* @author HUIHUI
*/
public interface BargainActivityService {
/**
* 创建砍价活动
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createBargainActivity(@Valid BargainActivityCreateReqVO createReqVO);
/**
* 更新砍价活动
*
* @param updateReqVO 更新信息
*/
void updateBargainActivity(@Valid BargainActivityUpdateReqVO updateReqVO);
/**
* 删除砍价活动
*
* @param id 编号
*/
void deleteBargainActivity(Long id);
/**
* 获得砍价活动
*
* @param id 编号
* @return 砍价活动
*/
BargainActivityDO getBargainActivity(Long id);
/**
* 获得砍价活动列表
*
* @param ids 编号
* @return 砍价活动列表
*/
List<BargainActivityDO> getBargainActivityList(Collection<Long> ids);
/**
* 获得砍价活动分页
*
* @param pageReqVO 分页查询
* @return 砍价活动分页
*/
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
/**
* 获得砍价活动商品列表
*
* @param ids 砍价活动 ids
* @return 砍价活动的商品列表
*/
List<BargainProductDO> getBargainProductsByActivityIds(Collection<Long> ids);
}

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
import java.time.LocalDateTime;
/**
* 商品活动记录 service
*
* @author HUIHUI
*/
public interface BargainRecordService {
/**
* 更新砍价状态
*
* @param userId 用户编号
* @param orderId 订单编号
* @param status 状态
*/
void updateBargainRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status);
///**
// * 创建砍价记录
// *
// * @param reqDTO 创建信息
// */
//void createBargainRecord(BargainRecordCreateReqDTO reqDTO);
/**
* 更新砍价状态和开始时间
*
* @param userId 用户编号
* @param orderId 订单编号
* @param status 状态
* @param startTime 开始时间
*/
void updateBargainRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId,
Integer status, LocalDateTime startTime);
/**
* 获得砍价状态
*
* @param userId 用户编号
* @param orderId 订单编号
* @return 砍价状态
*/
BargainRecordDO getBargainRecord(Long userId, Long orderId);
}

View File

@ -0,0 +1,293 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainRecordDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainActivityMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainProductMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.bargain.BargainRecordMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProductSkuAllExists;
/**
* 砍价活动 Service 实现类
*
* @author HUIHUI
*/
@Service
@Validated
public class BargainServiceImpl implements BargainActivityService, BargainRecordService {
@Resource
private BargainActivityMapper bargainActivityMapper;
@Resource
private BargainRecordMapper recordMapper;
@Resource
private BargainProductMapper bargainProductMapper;
@Resource
private ProductSpuApi productSpuApi;
@Resource
private ProductSkuApi productSkuApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) {
// 校验商品 SPU 是否存在是否参加的别的活动
validateProductBargainConflict(createReqVO.getSpuId(), null);
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(createReqVO.getSpuId()));
// 校验商品 sku 是否存在
validateProductSkuAllExists(skus, createReqVO.getProducts(), BargainProductCreateReqVO::getSkuId);
// 插入砍价活动
BargainActivityDO activityDO = BargainActivityConvert.INSTANCE.convert(createReqVO);
// TODO 营销相关属性初始化 砍价成功更新相关属性
activityDO.setSuccessCount(0);
// 活动总库存
activityDO.setStock(getSumValue(createReqVO.getProducts(), BargainProductCreateReqVO::getStock, Integer::sum));
activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
bargainActivityMapper.insert(activityDO);
// 插入商品
List<BargainProductDO> productDOs = BargainActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activityDO);
bargainProductMapper.insertBatch(productDOs);
// 返回
return activityDO.getId();
}
private void validateProductBargainConflict(Long spuId, Long activityId) {
// 校验商品 spu 是否存在
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
if (CollUtil.isEmpty(spuList)) {
throw exception(SPU_NOT_EXISTS);
}
// 查询所有开启的砍价活动
List<BargainActivityDO> activityDOs = bargainActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
// 更新时排除自己
if (activityId != null) {
activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
}
// 校验商品 spu 是否参加了其它活动
if (anyMatch(activityDOs, s -> ObjectUtil.equal(s.getId(), spuId))) {
throw exception(BARGAIN_ACTIVITY_SPU_CONFLICTS);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateBargainActivity(BargainActivityUpdateReqVO updateReqVO) {
// 校验存在
BargainActivityDO activityDO = validateBargainActivityExists(updateReqVO.getId());
// 校验状态
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
throw exception(BARGAIN_ACTIVITY_STATUS_DISABLE);
}
// 校验商品冲突
validateProductBargainConflict(updateReqVO.getSpuId(), updateReqVO.getId());
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(updateReqVO.getSpuId()));
// 校验商品 sku 是否存在
validateProductSkuAllExists(skus, updateReqVO.getProducts(), BargainProductUpdateReqVO::getSkuId);
// 更新
BargainActivityDO updateObj = BargainActivityConvert.INSTANCE.convert(updateReqVO);
// 更新活动库存
updateObj.setStock(getSumValue(updateReqVO.getProducts(), BargainProductUpdateReqVO::getStock, Integer::sum));
bargainActivityMapper.updateById(updateObj);
// 更新商品
updateBargainProduct(updateObj, updateReqVO.getProducts());
}
/**
* 更新砍价商品
*
* @param updateObj 更新的活动
* @param products 商品配置
*/
private void updateBargainProduct(BargainActivityDO updateObj, List<BargainProductUpdateReqVO> products) {
// 默认全部新增
List<BargainProductDO> defaultNewList = BargainActivityConvert.INSTANCE.convertList(products, updateObj);
// 数据库中的老数据
List<BargainProductDO> oldList = bargainProductMapper.selectListByActivityIds(CollUtil.newArrayList(updateObj.getId()));
List<List<BargainProductDO>> lists = CollectionUtils.diffList(oldList, defaultNewList, (oldVal, newVal) -> {
boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
if (same) {
newVal.setId(oldVal.getId());
}
return same;
});
// create
if (CollUtil.isNotEmpty(lists.get(0))) {
bargainProductMapper.insertBatch(lists.get(0));
}
// update
if (CollUtil.isNotEmpty(lists.get(1))) {
bargainProductMapper.updateBatch(lists.get(1));
}
// delete
if (CollUtil.isNotEmpty(lists.get(2))) {
bargainProductMapper.deleteBatchIds(CollectionUtils.convertList(lists.get(2), BargainProductDO::getId));
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteBargainActivity(Long id) {
// 校验存在
BargainActivityDO activityDO = validateBargainActivityExists(id);
// 校验状态
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
}
// 删除
bargainActivityMapper.deleteById(id);
}
private BargainActivityDO validateBargainActivityExists(Long id) {
BargainActivityDO activityDO = bargainActivityMapper.selectById(id);
if (activityDO == null) {
throw exception(BARGAIN_ACTIVITY_NOT_EXISTS);
}
return activityDO;
}
@Override
public BargainActivityDO getBargainActivity(Long id) {
return validateBargainActivityExists(id);
}
@Override
public List<BargainActivityDO> getBargainActivityList(Collection<Long> ids) {
return bargainActivityMapper.selectBatchIds(ids);
}
@Override
public PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO) {
return bargainActivityMapper.selectPage(pageReqVO);
}
@Override
public List<BargainProductDO> getBargainProductsByActivityIds(Collection<Long> ids) {
return bargainProductMapper.selectListByActivityIds(ids);
}
@Override
public void updateBargainRecordStatusByUserIdAndOrderId(Long userId, Long orderId, Integer status) {
// 校验砍价是否存在
// 更新状态
recordMapper.updateById(validateBargainRecord(userId, orderId).setStatus(status));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateBargainRecordStatusAndStartTimeByUserIdAndOrderId(Long userId, Long orderId, Integer status, LocalDateTime startTime) {
BargainRecordDO recordDO = validateBargainRecord(userId, orderId);
// 更新状态
recordDO.setStatus(status);
// 更新开始时间
//recordDO.setStartTime(startTime);
//recordMapper.updateById(recordDO);
//
//// 更新砍价参入人数
//List<BargainRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), status);
//if (CollUtil.isNotEmpty(recordDOs)) {
// recordDOs.forEach(item -> {
// item.setUserCount(recordDOs.size());
// // 校验砍价是否满足要求
// if (ObjectUtil.equal(recordDOs.size(), recordDO.getUserSize())) {
// item.setStatus(BargainRecordStatusEnum.SUCCESS.getStatus());
// }
// });
//}
//recordMapper.updateBatch(recordDOs);
}
private BargainRecordDO validateBargainRecord(Long userId, Long orderId) {
// 校验砍价是否存在
BargainRecordDO recordDO = recordMapper.selectRecord(userId, orderId);
if (recordDO == null) {
throw exception(BARGAIN_RECORD_NOT_EXISTS);
}
return recordDO;
}
//@Override
//public void createBargainRecord(BargainRecordCreateReqDTO reqDTO) {
// // 1.1 校验砍价活动
// BargainActivityDO activity = validateBargainActivityExists(reqDTO.getActivityId());
// // 1.2 需要校验下他当前是不是已经参加了该砍价
// BargainRecordDO recordDO = recordMapper.selectRecord(reqDTO.getUserId(), reqDTO.getOrderId());
// if (recordDO != null) {
// throw exception(BARGAIN_RECORD_EXISTS);
// }
// // 1.3 父砍价是否存在,是否已经满了
// if (reqDTO.getHeadId() != null) {
// BargainRecordDO recordDO1 = recordMapper.selectRecordByHeadId(reqDTO.getHeadId(), reqDTO.getActivityId(), BargainRecordStatusEnum.IN_PROGRESS.getStatus());
// if (recordDO1 == null) {
// throw exception(BARGAIN_RECORD_HEAD_NOT_EXISTS);
// }
// // 校验砍价是否满足要求
// if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
// throw exception(BARGAIN_RECORD_USER_FULL);
// }
// }
// // TODO @puhui999应该还有一些校验后续补噶例如说一个团自己已经参与进去了不能再参与进去
//
// // 2. 创建砍价记录
// BargainRecordDO record = BargainActivityConvert.INSTANCE.convert(reqDTO);
// if (reqDTO.getHeadId() == null) {
// // TODO @puhui999不是自己呀headId 是父团长的 BargainRecordDO.id
// record.setHeadId(reqDTO.getUserId());
// }
// record.setVirtualGroup(false);
// // TODO @puhui999过期时间应该是 Date
// record.setExpireTime(activity.getLimitDuration());
// record.setUserSize(activity.getUserSize());
// recordMapper.insert(record);
//}
@Override
public BargainRecordDO getBargainRecord(Long userId, Long orderId) {
return validateBargainRecord(userId, orderId);
}
/**
* APP 端获取开团记录
*
* @return 开团记录
*/
public List<BargainRecordDO> getRecordListByStatus(Integer status) {
return recordMapper.selectListByStatus(status);
}
}

View File

@ -2,12 +2,10 @@ package cn.iocoder.yudao.module.promotion.service.combination;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
@ -32,7 +30,8 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
@ -60,19 +59,20 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
private ProductSkuApi productSkuApi;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createCombinationActivity(CombinationActivityCreateReqVO createReqVO) {
// 校验商品 SPU 是否存在是否参加的别的活动
validateProductCombinationConflict(createReqVO.getSpuId(), null);
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(createReqVO.getSpuId()));
// 校验商品 sku 是否存在
validateProductSkuAllExists(createReqVO.getProducts(), skus, CombinationProductCreateReqVO::getSkuId);
validateProductSkuAllExists(skus, createReqVO.getProducts(), CombinationProductCreateReqVO::getSkuId);
// TODO 艿艿 有个小问题现在有活动时间和限制时长活动时间的结束时间早于设置的限制时间怎么算状态比如
// 活动时间 2023-08-05 15:00:00 - 2023-08-05 15:20:00 限制时长 2小时那么活动时间结束就结束还是加时到满两小时
// 插入拼团活动
CombinationActivityDO activityDO = CombinationActivityConvert.INSTANCE.convert(createReqVO);
// TODO 营销相关属性初始化
// TODO 营销相关属性初始化 拼团成功更新相关属性
activityDO.setTotalNum(0);
activityDO.setSuccessNum(0);
activityDO.setOrderUserCount(0);
@ -106,6 +106,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationActivity(CombinationActivityUpdateReqVO updateReqVO) {
// 校验存在
CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
@ -118,7 +119,7 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(updateReqVO.getSpuId()));
// 校验商品 sku 是否存在
validateProductSkuAllExists(updateReqVO.getProducts(), skus, CombinationProductUpdateReqVO::getSkuId);
validateProductSkuAllExists(skus, updateReqVO.getProducts(), CombinationProductUpdateReqVO::getSkuId);
// 更新
CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO);
@ -128,44 +129,40 @@ public class CombinationServiceImpl implements CombinationActivityService, Combi
}
/**
* 更新秒杀商品
* 更新拼团商品
*
* @param updateObj DO
* @param updateObj 更新的活动
* @param products 商品配置
*/
private void updateCombinationProduct(CombinationActivityDO updateObj, List<CombinationProductUpdateReqVO> products) {
List<CombinationProductDO> combinationProductDOs = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(updateObj.getId()));
// 数据库中的活动商品
Set<Long> convertSet = CollectionUtils.convertSet(combinationProductDOs, CombinationProductDO::getSkuId);
// 前端传过来的活动商品
Set<Long> convertSet1 = CollectionUtils.convertSet(products, CombinationProductUpdateReqVO::getSkuId);
// 分化数据
// TODO @芋艿看下这个实现
Map<String, List<CombinationProductDO>> data = CollectionUtils.convertCDUMap(convertSet1, convertSet, mapData -> {
HashMap<String, List<CombinationProductDO>> cdu = MapUtil.newHashMap(3);
MapUtils.findAndThen(mapData, "create", list -> {
cdu.put("create", CombinationActivityConvert.INSTANCE.convertList(CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
});
MapUtils.findAndThen(mapData, "delete", list -> {
cdu.put("create", CollectionUtils.filterList(combinationProductDOs, item -> list.contains(item.getSkuId())));
});
// TODO @芋艿临时注释避免有问题
// MapUtils.findAndThen(mapData, "update", list -> {
// cdu.put("update", CombinationActivityConvert.INSTANCE.convertList(
// combinationProductDOs,
// CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
// });
return cdu;
// 默认全部新增
List<CombinationProductDO> defaultNewList = CombinationActivityConvert.INSTANCE.convertList(products, updateObj);
// 数据库中的老数据
List<CombinationProductDO> oldList = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(updateObj.getId()));
List<List<CombinationProductDO>> lists = CollectionUtils.diffList(oldList, defaultNewList, (oldVal, newVal) -> {
boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
if (same) {
newVal.setId(oldVal.getId());
}
return same;
});
// 执行增删改
MapUtils.findAndThen(data, "create", item -> combinationProductMapper.insertBatch(item));
MapUtils.findAndThen(data, "delete", item -> combinationProductMapper.deleteBatchIds(
CollectionUtils.convertSet(item, CombinationProductDO::getId)));
MapUtils.findAndThen(data, "update", item -> combinationProductMapper.updateBatch(item));
// create
if (CollUtil.isNotEmpty(lists.get(0))) {
combinationProductMapper.insertBatch(lists.get(0));
}
// update
if (CollUtil.isNotEmpty(lists.get(1))) {
combinationProductMapper.updateBatch(lists.get(1));
}
// delete
if (CollUtil.isNotEmpty(lists.get(2))) {
combinationProductMapper.deleteBatchIds(CollectionUtils.convertList(lists.get(2), CombinationProductDO::getId));
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteCombinationActivity(Long id) {
// 校验存在
CombinationActivityDO activityDO = validateCombinationActivityExists(id);

View File

@ -1,12 +1,9 @@
package cn.iocoder.yudao.module.promotion.service.seckill.seckillactivity;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
@ -28,9 +25,13 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
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.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@ -71,7 +72,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
// 插入秒杀活动
SeckillActivityDO activity = SeckillActivityConvert.INSTANCE.convert(createReqVO)
.setStatus(PromotionUtils.calculateActivityStatus(createReqVO.getEndTime()))
.setTotalStock(CollectionUtils.getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
.setTotalStock(getSumValue(createReqVO.getProducts(), SeckillProductCreateReqVO::getStock, Integer::sum));
seckillActivityMapper.insert(activity);
// 插入商品
List<SeckillProductDO> products = SeckillActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
@ -94,16 +95,16 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
}
// 过滤出所有 spuId 有交集的活动
List<SeckillActivityDO> activityDOs1 = CollectionUtils.convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId));
if (CollUtil.isNotEmpty(activityDOs1)) {
List<SeckillActivityDO> activityDOs1 = convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getSpuId(), spuId));
if (isNotEmpty(activityDOs1)) {
throw exception(SECKILL_ACTIVITY_SPU_CONFLICTS);
}
List<SeckillActivityDO> activityDOs2 = CollectionUtils.convertList(activityDOs, c -> c, s -> {
List<SeckillActivityDO> activityDOs2 = convertList(activityDOs, c -> c, s -> {
// 判断秒杀时段是否有交集
return CollectionUtils.containsAny(s.getConfigIds(), configIds);
return containsAny(s.getConfigIds(), configIds);
});
if (CollUtil.isNotEmpty(activityDOs2)) {
if (isNotEmpty(activityDOs2)) {
throw exception(SECKILL_TIME_CONFLICTS);
}
}
@ -121,12 +122,12 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollUtil.newArrayList(updateReqVO.getSpuId()));
// 校验商品 sku 是否存在
validateProductSkuAllExists(updateReqVO.getProducts(), skus, SeckillProductUpdateReqVO::getSkuId);
validateProductSkuAllExists(skus, updateReqVO.getProducts(), SeckillProductUpdateReqVO::getSkuId);
// 更新活动
SeckillActivityDO updateObj = SeckillActivityConvert.INSTANCE.convert(updateReqVO)
.setStatus(PromotionUtils.calculateActivityStatus(updateReqVO.getEndTime()))
.setTotalStock(CollectionUtils.getSumValue(updateReqVO.getProducts(), SeckillProductUpdateReqVO::getStock, Integer::sum));
.setTotalStock(getSumValue(updateReqVO.getProducts(), SeckillProductUpdateReqVO::getStock, Integer::sum));
seckillActivityMapper.updateById(updateObj);
// 更新商品
updateSeckillProduct(updateObj, updateReqVO.getProducts());
@ -139,36 +140,32 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
* @param updateObj 更新的活动
* @param products 商品配置
*/
// TODO @puhui999我在想我们是不是可以封装一个 CollUtil 的方法传入两个数组判断出哪些是新增哪些是修改哪些是删除
// 例如说products 先转化成 SeckillProductDO然后基于一个 func(key1, key2) 做比对
// 如果可以跑通所有涉及到这种逻辑的都可以服用哈
private void updateSeckillProduct(SeckillActivityDO updateObj, List<SeckillProductUpdateReqVO> products) {
// 默认全部新增
List<SeckillProductDO> defaultNewList = SeckillActivityConvert.INSTANCE.convertList(products, updateObj);
// 数据库中的活动商品
List<SeckillProductDO> seckillProductDOs = seckillProductMapper.selectListByActivityId(updateObj.getId());
Set<Long> dbSkuIds = CollectionUtils.convertSet(seckillProductDOs, SeckillProductDO::getSkuId);
Set<Long> voSkuIds = CollectionUtils.convertSet(products, SeckillProductUpdateReqVO::getSkuId);
Map<String, List<SeckillProductDO>> data = CollectionUtils.convertCDUMap(voSkuIds, dbSkuIds, mapData -> {
HashMap<String, List<SeckillProductDO>> cdu = MapUtil.newHashMap(3);
MapUtils.findAndThen(mapData, "create", list -> {
cdu.put("create", SeckillActivityConvert.INSTANCE.convertList(
CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
});
MapUtils.findAndThen(mapData, "delete", list -> {
cdu.put("create", CollectionUtils.filterList(seckillProductDOs, item -> list.contains(item.getSkuId())));
});
// TODO @芋艿临时注释
// MapUtils.findAndThen(mapData, "update", list -> {
// cdu.put("update", SeckillActivityConvert.INSTANCE.convertList(seckillProductDOs,
// CollectionUtils.filterList(products, item -> list.contains(item.getSkuId())), updateObj));
// });
return cdu;
List<SeckillProductDO> oldList = seckillProductMapper.selectListByActivityId(updateObj.getId());
// 对比老新两个列表找出新增修改删除的数据
List<List<SeckillProductDO>> lists = diffList(oldList, defaultNewList, (oldVal, newVal) -> {
boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
if (same) {
newVal.setId(oldVal.getId());
}
return same;
});
// 执行增删改
MapUtils.findAndThen(data, "create", item -> seckillProductMapper.insertBatch(item));
MapUtils.findAndThen(data, "delete", item -> seckillProductMapper.deleteBatchIds(
CollectionUtils.convertSet(item, SeckillProductDO::getId)));
MapUtils.findAndThen(data, "update", item -> seckillProductMapper.updateBatch(item));
// create
if (isNotEmpty(lists.get(0))) {
seckillProductMapper.insertBatch(lists.get(0));
}
// update
if (isNotEmpty(lists.get(1))) {
seckillProductMapper.updateBatch(lists.get(1));
}
// delete
if (isNotEmpty(lists.get(2))) {
seckillProductMapper.deleteBatchIds(convertList(lists.get(2), SeckillProductDO::getId));
}
}
@Override
@ -198,7 +195,7 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
seckillActivityMapper.deleteById(id);
// 删除活动商品
List<SeckillProductDO> productDOs = seckillProductMapper.selectListByActivityId(id);
Set<Long> convertSet = CollectionUtils.convertSet(productDOs, SeckillProductDO::getSkuId);
Set<Long> convertSet = convertSet(productDOs, SeckillProductDO::getSkuId);
seckillProductMapper.deleteBatchIds(convertSet);
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.promotion.util;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
@ -12,6 +11,7 @@ import java.util.Set;
import java.util.function.Function;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS;
/**
@ -31,22 +31,19 @@ public class PromotionUtils {
return LocalDateTimeUtils.beforeNow(endTime) ? CommonStatusEnum.DISABLE.getStatus() : CommonStatusEnum.ENABLE.getStatus();
}
// TODO @puhui999是不是第一个参数是 sku然后是 products这样关联性好点
/**
* 校验商品 sku 是否都存在
*
* @param products 需要校验的商品
* @param skus 数据库中的商品 skus
* @param products 需要校验的商品
* @param func 获取需要校验的商品的 skuId
*/
public static <T> void validateProductSkuAllExists(List<T> products, List<ProductSkuRespDTO> skus, Function<T, Long> func) {
public static <T> void validateProductSkuAllExists(List<ProductSkuRespDTO> skus, List<T> products, Function<T, Long> func) {
// 校验 sku 个数是否一致
Set<Long> skuIdsSet = CollectionUtils.convertSet(products, func);
Set<Long> skuIdsSet1 = CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId);
// 校验 skuId 是否存在
// TODO @puhui999findFirst
List<Long> f = CollectionUtils.filterList(skuIdsSet, s -> !skuIdsSet1.contains(s));
if (CollUtil.isNotEmpty(f)) {
if (anyMatch(skuIdsSet, s -> !skuIdsSet1.contains(s))) {
throw exception(SKU_NOT_EXISTS);
}
}

View File

@ -3,12 +3,10 @@ package cn.iocoder.yudao.module.trade.service.order;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.member.api.address.AddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
@ -59,9 +57,10 @@ import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import static cn.hutool.core.util.ObjectUtil.equal;
import static cn.hutool.core.util.ObjectUtil.notEqual;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@ -171,7 +170,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
// 3.3 校验订单类型
// 拼团
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
if (equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
MemberUserRespDTO user = memberUserApi.getUser(userId);
// TODO 拼团一次应该只能选择一种规格的商品
// TODO @puhui999应该是前置校验哈然后不应该设置状态而是交给拼团记录那处理
@ -179,7 +178,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
.setStatus(CombinationRecordStatusEnum.WAITING.getStatus()));
}
// TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
if (ObjectUtil.equal(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
if (equal(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
}
@ -206,7 +205,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
TradePriceCalculateRespBO calculateRespBO) {
// 用户选择物流配送的时候才需要填写收货地址
AddressRespDTO address = new AddressRespDTO();
if (ObjectUtil.equal(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getMode())) {
if (equal(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getMode())) {
// 用户收件地址的校验
address = validateAddress(userId, createReqVO.getAddressId());
}
@ -310,7 +309,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
}
// 校验活动
// 1拼团活动
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
if (equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
// 更新拼团状态 TODO puhui999订单支付失败或订单支付过期删除这条拼团记录
combinationRecordApi.updateCombinationRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
}
@ -344,7 +343,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
}
// 校验支付订单匹配
if (ObjectUtil.notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
if (notEqual(order.getPayOrderId(), payOrderId)) { // 支付单号
log.error("[validateOrderPaid][order({}) 支付单不匹配({})请进行处理order 数据是:{}]",
id, payOrderId, JsonUtils.toJsonString(order));
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
@ -363,13 +362,13 @@ public class TradeOrderServiceImpl implements TradeOrderService {
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_STATUS_NOT_SUCCESS);
}
// 校验支付金额一致
if (ObjectUtil.notEqual(payOrder.getPrice(), order.getPayPrice())) {
if (notEqual(payOrder.getPrice(), order.getPayPrice())) {
log.error("[validateOrderPaid][order({}) payOrder({}) 支付金额不匹配请进行处理order 数据是:{}payOrder 数据是:{}]",
id, payOrderId, JsonUtils.toJsonString(order), JsonUtils.toJsonString(payOrder));
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_PRICE_NOT_MATCH);
}
// 校验支付订单匹配二次
if (ObjectUtil.notEqual(payOrder.getMerchantOrderId(), id.toString())) {
if (notEqual(payOrder.getMerchantOrderId(), id.toString())) {
log.error("[validateOrderPaid][order({}) 支付单不匹配({})请进行处理payOrder 数据是:{}]",
id, payOrderId, JsonUtils.toJsonString(payOrder));
throw exception(ORDER_UPDATE_PAID_FAIL_PAY_ORDER_ID_ERROR);
@ -393,7 +392,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
TradeOrderDO updateOrderObj = new TradeOrderDO();
// 判断发货类型
// 2.1 快递发货
if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.EXPRESS.getMode())) {
if (equal(deliveryReqVO.getType(), DeliveryTypeEnum.EXPRESS.getMode())) {
// 校验快递公司
// TODO @puhui999getDeliveryExpress 直接封装一个校验的会不会好点因为还有开启关闭啥的
DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
@ -403,13 +402,13 @@ public class TradeOrderServiceImpl implements TradeOrderService {
updateOrderObj.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
}
// 2.2 用户自提
if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.PICK_UP.getMode())) {
if (equal(deliveryReqVO.getType(), DeliveryTypeEnum.PICK_UP.getMode())) {
// TODO 校验自提门店是否存在
// 重置一下确保快递公司和快递单号为空
updateOrderObj.setLogisticsId(null).setLogisticsNo("");
}
// 2.3 TODO 芋艿如果无需发货需要怎么存储回复需要把 deliverType 设置为 DeliveryTypeEnum.NULL
if (ObjectUtil.equal(deliveryReqVO.getType(), DeliveryTypeEnum.NULL.getMode())) {
if (equal(deliveryReqVO.getType(), DeliveryTypeEnum.NULL.getMode())) {
// TODO 情况一正常走发货逻辑和用户自提有点像 不同点不需要自提门店只需要用户确认收货
// TODO 情况二用户下单付款后直接确认收货或等待用户确认收货
// 重置一下确保快递公司和快递单号为空
@ -449,15 +448,15 @@ public class TradeOrderServiceImpl implements TradeOrderService {
}
// 校验订单是否是待发货状态
if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())
|| ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) {
|| notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus())) {
throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
}
// 校验订单是否退款
if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
if (notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
}
// 订单类型拼团
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
if (equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
// 校验订单拼团是否成功
// TODO 用户 ID 使用当前登录用户的还是订单保存的
if (combinationRecordApi.isCombinationRecordSuccess(order.getUserId(), order.getId())) {
@ -510,7 +509,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
}
// 校验订单是否是待收货状态
if (!TradeOrderStatusEnum.isDelivered(order.getStatus())
|| ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.DELIVERED.getStatus())) {
|| notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.DELIVERED.getStatus())) {
throw exception(ORDER_RECEIVE_FAIL_STATUS_NOT_DELIVERED);
}
return order;
@ -520,7 +519,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
public TradeOrderDO getOrder(Long userId, Long id) {
TradeOrderDO order = tradeOrderMapper.selectById(id);
if (order != null
&& ObjectUtil.notEqual(order.getUserId(), userId)) {
&& notEqual(order.getUserId(), userId)) {
return null;
}
return order;
@ -564,7 +563,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
public TradeOrderItemDO getOrderItem(Long userId, Long itemId) {
TradeOrderItemDO orderItem = tradeOrderItemMapper.selectById(itemId);
if (orderItem != null
&& ObjectUtil.notEqual(orderItem.getUserId(), userId)) {
&& notEqual(orderItem.getUserId(), userId)) {
return null;
}
return orderItem;
@ -644,10 +643,10 @@ public class TradeOrderServiceImpl implements TradeOrderService {
if (order == null) {
throw exception(ORDER_NOT_FOUND);
}
if (ObjectUtil.notEqual(order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) {
if (notEqual(order.getStatus(), TradeOrderStatusEnum.COMPLETED.getStatus())) {
throw exception(ORDER_COMMENT_FAIL_STATUS_NOT_COMPLETED);
}
if (ObjectUtil.notEqual(order.getCommentStatus(), Boolean.FALSE)) {
if (notEqual(order.getCommentStatus(), Boolean.FALSE)) {
throw exception(ORDER_COMMENT_STATUS_NOT_FALSE);
}
@ -657,7 +656,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// 更新订单项评价状态
tradeOrderItemMapper.updateById(new TradeOrderItemDO().setId(orderItem.getId()).setCommentStatus(Boolean.TRUE));
List<TradeOrderItemDO> orderItems = getOrderItemListByOrderId(CollUtil.newArrayList(order.getId()));
if (!CollectionUtils.isAny(orderItems, item -> ObjectUtil.equal(item.getCommentStatus(), Boolean.FALSE))) {
if (!anyMatch(orderItems, item -> equal(item.getCommentStatus(), Boolean.FALSE))) {
// 对于 order 来说就是评论完 order 更新完合理的 status 等字段
tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setCommentStatus(Boolean.TRUE));
}