!571 完善订单发货逻辑、重构砍价活动、完善拼团记录创建逻辑

Merge pull request !571 from puhui999/feature/mall_product
This commit is contained in:
芋道源码 2023-08-15 12:29:51 +00:00 committed by Gitee
commit 60171ce7e4
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
37 changed files with 391 additions and 501 deletions

View File

@ -14,10 +14,19 @@ import javax.validation.Valid;
public interface BargainRecordApi {
/**
* 创建开团记录
* 创建砍价记录
*
* @param reqDTO 请求 DTO
*/
void createRecord(@Valid BargainRecordCreateReqDTO reqDTO);
/**
* 查询砍价是否成功
*
* @param userId 用户编号
* @param orderId 订单编号
* @return 砍价是否成功
*/
boolean validateRecordSuccess(Long userId, Long orderId);
}

View File

@ -1,11 +1,14 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
import javax.validation.Valid;
import java.util.List;
// TODO @芋艿后面也再撸撸这几个接口
/**
* 拼团记录 API 接口
*
@ -18,7 +21,7 @@ public interface CombinationRecordApi {
*
* @param reqDTO 请求 DTO
*/
void createCombinationRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
void createRecord(@Valid CombinationRecordCreateReqDTO reqDTO);
/**
* 查询拼团记录是否成功
@ -27,7 +30,26 @@ public interface CombinationRecordApi {
* @param orderId 订单编号
* @return 拼团是否成功
*/
boolean isCombinationRecordSuccess(Long userId, Long orderId);
boolean validateRecordSuccess(Long userId, Long orderId);
/**
* 获取拼团记录
*
* @param userId 用户编号
* @param activityId 活动编号
* @return 拼团记录列表
*/
List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
/**
* 验证组合限制数
* 校验是否满足限购要求
*
* @param count 本次购买数量
* @param sumCount 已购买数量合计
* @param activityId 活动编号
*/
void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
// TODO @puhui999是不是搞成具体的方法拼团成功拼团失败这种方法

View File

@ -0,0 +1,46 @@
package cn.iocoder.yudao.module.promotion.api.combination.dto;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* 拼团记录 Response DTO
*
* @author HUIHUI
*/
@Data
public class CombinationRecordRespDTO {
/**
* 拼团活动编号
*/
@NotNull(message = "拼团活动编号不能为空")
private Long activityId;
/**
* spu 编号
*/
@NotNull(message = "spu 编号不能为空")
private Long spuId;
/**
* sku 编号
*/
@NotNull(message = "sku 编号不能为空")
private Long skuId;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 订单编号
*/
@NotNull(message = "订单编号不能为空")
private Long orderId;
/**
* 开团状态正在开团 拼团成功 拼团失败
*/
@NotNull(message = "开团状态不能为空")
private Integer status;
}

View File

@ -64,17 +64,18 @@ public interface ErrorCodeConstants {
ErrorCode COMBINATION_RECORD_NOT_EXISTS = new ErrorCode(1013010004, "拼团不存在");
ErrorCode COMBINATION_RECORD_EXISTS = new ErrorCode(1013010005, "拼团失败,已参与过该拼团");
ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1013010006, "拼团失败,父拼团不存在");
ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013010006, "拼团失败,拼团人数已满");
ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1013010007, "拼团失败,拼团人数已满");
ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1013010008, "拼团失败,已参与其它拼团");
ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1013010009, "拼团失败,活动已经结束");
ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1013010010, "拼团失败,单次限购超出");
ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1013010011, "拼团失败,单次限购超出");
// ========== 砍价活动 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, "砍价活动未关闭或未结束,不能删除");
// TODO @puhui999拆分成砍价记录
ErrorCode BARGAIN_RECORD_NOT_EXISTS = new ErrorCode(1013011004, "砍价不存在");
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,24 @@
package cn.iocoder.yudao.module.promotion.api.bargain;
import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainRecordCreateReqDTO;
import org.springframework.stereotype.Service;
/**
* 砍价活动 API 实现类 TODO @puhui999
*
* @author HUIHUI
*/
@Service
public class BargainRecordApiImpl implements BargainRecordApi {
@Override
public void createRecord(BargainRecordCreateReqDTO reqDTO) {
}
@Override
public boolean validateRecordSuccess(Long userId, Long orderId) {
return false;
}
}

View File

@ -1,12 +1,15 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* 拼团活动 API 实现类
@ -20,15 +23,25 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
private CombinationRecordService recordService;
@Override
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
public void createRecord(CombinationRecordCreateReqDTO reqDTO) {
recordService.createCombinationRecord(reqDTO);
}
@Override
public boolean isCombinationRecordSuccess(Long userId, Long orderId) {
public boolean validateRecordSuccess(Long userId, Long orderId) {
return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus());
}
@Override
public List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId) {
return CombinationActivityConvert.INSTANCE.convert(recordService.getRecordListByUserIdAndActivityId(userId, activityId));
}
@Override
public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {
recordService.validateCombinationLimitCount(activityId, count, sumCount);
}
@Override
public void updateCombinationRecordStatus(CombinationRecordUpdateStatusReqDTO reqDTO) {
if (null == reqDTO.getStartTime()) {

View File

@ -4,14 +4,12 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.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.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.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;
@ -22,12 +20,8 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
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
@ -44,7 +38,7 @@ public class BargainActivityController {
@PostMapping("/create")
@Operation(summary = "创建砍价活动")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:create')")
public CommonResult<Long> createBargainActivity(@Valid @RequestBody BargainActivityCreateReqVO createReqVO) {
public CommonResult<Long> createBargainActivity(@Valid @RequestBody BargainActivityBaseVO createReqVO) {
return success(activityService.createBargainActivity(createReqVO));
}
@ -70,9 +64,7 @@ public class BargainActivityController {
@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));
return success(BargainActivityConvert.INSTANCE.convert(activityService.getBargainActivity(id)));
}
@GetMapping("/page")
@ -85,14 +77,7 @@ public class BargainActivityController {
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
// 拼接数据
// List<BargainProductDO> products = activityService.getBargainProductsByActivityIds(
// convertSet(pageResult.getList(), BargainActivityDO::getId));
List<BargainProductDO> products = Collections.emptyList();
List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(
convertSet(pageResult.getList(), BargainActivityDO::getSpuId));
return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, products, spus));
return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO)));
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@ -26,6 +26,22 @@ public class BargainActivityBaseVO {
@NotNull(message = "砍价商品不能为空")
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;
@Schema(description = "总限购数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16218")
@NotNull(message = "总限购数量不能为空")
private Integer totalLimitCount;

View File

@ -1,15 +1,10 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
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
@ -20,14 +15,6 @@ public class BargainActivityPageReqVO extends PageParam {
@Schema(description = "砍价名称", example = "赵六")
private String name;
@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 = "活动状态0开启 1关闭", example = "0")
private Integer status;

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
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;
@ -8,8 +7,6 @@ import lombok.ToString;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;
@Schema(description = "管理后台 - 砍价活动 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ -25,17 +22,14 @@ public class BargainActivityRespVO extends BargainActivityBaseVO {
@Schema(description = "活动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22901")
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59")
private LocalDateTime createTime;
@Schema(description = "砍价成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
@Schema(description = "砍价成功数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "999")
private Integer successCount;
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "活动状态不能为空")
private Integer status;
@Schema(description = "砍价商品", requiredMode = Schema.RequiredMode.REQUIRED)
private List<BargainProductRespVO> products;
}

View File

@ -1,14 +1,11 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductBaseVO;
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
@ -20,8 +17,4 @@ public class BargainActivityUpdateReqVO extends BargainActivityBaseVO {
@NotNull(message = "活动编号不能为空")
private Long id;
@Schema(description = "砍价商品", requiredMode = Schema.RequiredMode.REQUIRED)
@Valid
private List<BargainProductBaseVO> products;
}

View File

@ -1,22 +0,0 @@
package cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.product.BargainProductBaseVO;
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<BargainProductBaseVO> products;
}

View File

@ -1,35 +0,0 @@
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 = "44")
@NotNull(message = "商品 skuId 不能为空")
private Long skuId;
@Schema(description = "砍价起始价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "33")
@NotNull(message = "砍价起始价格不能为空")
private Integer bargainFirstPrice;
@Schema(description = "砍价底价", requiredMode = Schema.RequiredMode.REQUIRED, example = "22")
@NotNull(message = "砍价底价不能为空")
private Integer bargainPrice;
@Schema(description = "活动库存", requiredMode = Schema.RequiredMode.REQUIRED, example = "11")
@NotNull(message = "活动库存不能为空")
private Integer stock;
}

View File

@ -1,22 +0,0 @@
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

@ -5,11 +5,6 @@ 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
@ -20,15 +15,8 @@ public class CombinationActivityPageReqVO extends PageParam {
@Schema(description = "拼团名称", example = "赵六")
private String name;
@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 = "活动状态0开启 1关闭", example = "0")
private Integer status;
}

View File

@ -1,25 +1,14 @@
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.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
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
@ -31,62 +20,14 @@ public interface BargainActivityConvert {
BargainActivityConvert INSTANCE = Mappers.getMapper(BargainActivityConvert.class);
BargainActivityDO convert(BargainActivityCreateReqVO bean);
BargainActivityDO convert(BargainActivityBaseVO bean);
BargainActivityDO convert(BargainActivityUpdateReqVO bean);
BargainActivityRespVO convert(BargainActivityDO bean);
BargainProductRespVO convert(BargainProductDO bean);
default BargainActivityRespVO convert(BargainActivityDO activity,
List<BargainProductDO> products) {
return convert(activity).setProducts(convertList2(products));
}
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) {
PageResult<BargainActivityRespVO> pageResult = convertPage(page);
// 拼接商品
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
pageResult.getList().forEach(item -> {
item.setProducts(convertList2(productList));
MapUtils.findAndThen(spuMap, item.getSpuId(),
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()));
});
return pageResult;
}
List<BargainProductRespVO> convertList2(List<BargainProductDO> productDOs);
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(target = "activityId", source = "activity.id"),
@Mapping(target = "spuId", source = "activity.spuId"),
@Mapping(target = "skuId", source = "product.skuId"),
@Mapping(target = "bargainFirstPrice", source = "product.bargainFirstPrice"),
@Mapping(target = "bargainPrice", source = "product.bargainPrice"),
@Mapping(target = "stock", source = "product.stock"),
@Mapping(target = "activityStartTime", source = "activity.startTime"),
@Mapping(target = "activityEndTime", source = "activity.endTime")
})
BargainProductDO convert(BargainActivityDO activity, BargainProductBaseVO product);
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<BargainProductBaseVO> 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()));
}
}

View File

@ -5,6 +5,7 @@ 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.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@ -41,9 +42,8 @@ public interface CombinationActivityConvert {
CombinationProductRespVO convert(CombinationProductDO bean);
default CombinationActivityRespVO convert(CombinationActivityDO activity,
List<CombinationProductDO> products) {
return convert(activity).setProducts(convertList2(products));
default CombinationActivityRespVO convert(CombinationActivityDO bean, List<CombinationProductDO> productDOs) {
return convert(bean).setProducts(convertList2(productDOs));
}
List<CombinationActivityRespVO> convertList(List<CombinationActivityDO> list);
@ -53,22 +53,20 @@ public interface CombinationActivityConvert {
default PageResult<CombinationActivityRespVO> convertPage(PageResult<CombinationActivityDO> page,
List<CombinationProductDO> productList,
List<ProductSpuRespDTO> spuList) {
PageResult<CombinationActivityRespVO> pageResult = convertPage(page);
// 拼接商品
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
PageResult<CombinationActivityRespVO> 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));
MapUtils.findAndThen(spuMap, item.getSpuId(),
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()));
});
return pageResult;
}
List<CombinationProductRespVO> convertList2(List<CombinationProductDO> productDOs);
default List<CombinationProductDO> convertList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activityDO) {
return CollectionUtils.convertList(products, item -> convert(activityDO, item).setActivityStatus(activityDO.getStatus()));
}
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(target = "activityId", source = "activity.id"),
@ -80,6 +78,10 @@ public interface CombinationActivityConvert {
})
CombinationProductDO convert(CombinationActivityDO activity, CombinationProductBaseVO product);
default List<CombinationProductDO> convertList(List<? extends CombinationProductBaseVO> products, CombinationActivityDO activity) {
return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus()));
}
default List<CombinationProductDO> convertList(List<CombinationProductBaseVO> updateProductVOs,
List<CombinationProductDO> products, CombinationActivityDO activity) {
Map<Long, Long> productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId);
@ -90,4 +92,6 @@ public interface CombinationActivityConvert {
CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);
}

View File

@ -20,8 +20,6 @@ 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
*
@ -40,32 +38,28 @@ public interface SeckillActivityConvert {
List<SeckillActivityRespVO> convertList(List<SeckillActivityDO> list);
default PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page,
List<SeckillProductDO> seckillProducts,
List<ProductSpuRespDTO> spuList) {
PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
default PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page, List<SeckillProductDO> seckillProducts, List<ProductSpuRespDTO> spuList) {
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
PageResult<SeckillActivityRespVO> pageResult = convertPage(page);
// 拼接商品
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
pageResult.getList().forEach(item -> {
MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> {
item.setSpuName(spu.getName());
item.setPicUrl(spu.getPicUrl());
});
item.setProducts(convertList2(seckillProducts));
MapUtils.findAndThen(spuMap, item.getSpuId(),
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()));
});
return pageResult;
}
PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
SeckillActivityDetailRespVO convert1(SeckillActivityDO seckillActivity);
default SeckillActivityDetailRespVO convert(SeckillActivityDO activity,
List<SeckillProductDO> products) {
return convert1(activity).setProducts(convertList2(products));
default SeckillActivityDetailRespVO convert(SeckillActivityDO seckillActivity, List<SeckillProductDO> seckillProducts) {
return convert1(seckillActivity).setProducts(convertList2(seckillProducts));
}
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> productDOs);
default List<SeckillProductDO> convertList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activityDO) {
return CollectionUtils.convertList(products, item -> convert(activityDO, item).setActivityStatus(activityDO.getStatus()));
}
@Mappings({
@Mapping(target = "id", ignore = true),
@Mapping(target = "activityId", source = "activity.id"),
@ -79,4 +73,10 @@ public interface SeckillActivityConvert {
})
SeckillProductDO convert(SeckillActivityDO activity, SeckillProductBaseVO product);
default List<SeckillProductDO> convertList(List<? extends SeckillProductBaseVO> products, SeckillActivityDO activity) {
return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus()));
}
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> productDOs);
}

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.promotion.dal.dataobject.bargain;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
@ -29,6 +28,7 @@ public class BargainActivityDO extends BaseDO {
*/
@TableId
private Long id;
/**
* 砍价活动名称
*/
@ -38,6 +38,7 @@ public class BargainActivityDO extends BaseDO {
* 活动开始时间
*/
private LocalDateTime startTime;
/**
* 活动结束时间
*/
@ -45,8 +46,6 @@ public class BargainActivityDO extends BaseDO {
/**
* 活动状态
*
* 枚举 {@link CommonStatusEnum}
*/
private Integer status;
@ -55,35 +54,50 @@ public class BargainActivityDO extends BaseDO {
*/
private Long spuId;
/**
* 砍价库存
* 商品 SKU 编号
*/
private Integer stock;
private Long skuId;
/**
* 砍价起始价格单位分
*/
private Integer bargainFirstPrice;
/**
* 砍价底价单位
*/
private Integer bargainPrice;
/**
* 达到该人数才能砍到低价
*/
private Integer userSize;
/**
* 最大帮砍次数
*/
private Integer bargainCount;
/**
* 总限购数量
*/
private Integer totalLimitCount;
/**
* 砍价活动库存
*/
private Integer stock;
/**
* 用户每次砍价的最小金额单位
*/
private Integer randomMinPrice;
/**
* 用户每次砍价的最大金额单位
*/
private Integer randomMaxPrice;
/**
* 砍价成功数量
*/
private Integer successCount;
// TODO @puhui999 BargainProductDO 字段融合过来
}

View File

@ -1,71 +0,0 @@
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
*/
@Deprecated // 应该融合到 BargainActivityDO
@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

@ -3,7 +3,7 @@ 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.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import org.apache.ibatis.annotations.Mapper;
@ -20,6 +20,7 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
default PageResult<BargainActivityDO> selectPage(BargainActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BargainActivityDO>()
.likeIfPresent(BargainActivityDO::getName, reqVO.getName())
.eqIfPresent(BargainActivityDO::getStatus, reqVO.getStatus())
.orderByDesc(BargainActivityDO::getId));
}

View File

@ -1,22 +0,0 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
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 List<BargainProductDO> selectListByActivityIds(Collection<Long> ids) {
return selectList(BargainProductDO::getActivityId, ids);
}
}

View File

@ -20,8 +20,6 @@ public interface CombinationActivityMapper extends BaseMapperX<CombinationActivi
default PageResult<CombinationActivityDO> selectPage(CombinationActivityPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CombinationActivityDO>()
.likeIfPresent(CombinationActivityDO::getName, reqVO.getName())
.betweenIfPresent(CombinationActivityDO::getStartTime, reqVO.getStartTime())
.betweenIfPresent(CombinationActivityDO::getEndTime, reqVO.getEndTime())
.eqIfPresent(CombinationActivityDO::getStatus, reqVO.getStatus())
.orderByDesc(CombinationActivityDO::getId));
}

View File

@ -20,18 +20,20 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
CombinationRecordDO::getOrderId, orderId);
}
// TODO @puhui999 selectByUserIdAndActivityId
default List<CombinationRecordDO> selectListByUserIdAndStatus(Long userId, Integer status) {
return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getUserId, userId)
.eq(CombinationRecordDO::getStatus, status));
}
/**
* 查询拼团记录
*
* @param headId 团长编号
* @param activityId 活动编号
* @param headId 团长编号
* @return 拼团记录
*/
default CombinationRecordDO selectRecordByHeadId(Long headId, Long activityId, Integer status) {
default CombinationRecordDO selectOneByHeadId(Long headId, Integer status) {
return selectOne(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getUserId, headId)
.eq(CombinationRecordDO::getActivityId, activityId)
.eq(CombinationRecordDO::getId, headId)
.eq(CombinationRecordDO::getStatus, status));
}
@ -45,4 +47,16 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
return selectList(CombinationRecordDO::getStatus, status);
}
/**
* 查询拼团记录
*
* @param userId 用户 id
* @param activityId 活动 id
* @return 拼团记录
*/
default List<CombinationRecordDO> selectListByUserIdAndActivityId(Long userId, Long activityId) {
return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
.eq(CombinationRecordDO::getUserId, userId)
.eq(CombinationRecordDO::getActivityId, activityId));
}
}

View File

@ -1,15 +1,12 @@
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.controller.admin.bargain.vo.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.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 接口
@ -24,7 +21,7 @@ public interface BargainActivityService {
* @param createReqVO 创建信息
* @return 编号
*/
Long createBargainActivity(@Valid BargainActivityCreateReqVO createReqVO);
Long createBargainActivity(@Valid BargainActivityBaseVO createReqVO);
/**
* 更新砍价活动
@ -56,12 +53,5 @@ public interface BargainActivityService {
*/
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
/**
* 获得砍价活动商品列表
*
* @param activityIds 砍价活动 ids
* @return 砍价活动的商品列表
*/
List<BargainProductDO> getBargainProductsByActivityIds(Collection<Long> activityIds);
}

View File

@ -10,29 +10,25 @@ 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.BargainProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.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.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.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.SKU_NOT_EXISTS;
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 实现类
@ -43,42 +39,43 @@ import static cn.iocoder.yudao.module.promotion.util.PromotionUtils.validateProd
@Validated
public class BargainActivityServiceImpl implements BargainActivityService {
@Resource
private BargainActivityMapper bargainActivityMapper;
@Resource
private BargainProductMapper bargainProductMapper;
private BargainRecordMapper recordMapper;
@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()));
private static void validateSku(Long skuId, List<ProductSkuRespDTO> skus) {
// 校验商品 sku 是否存在
validateProductSkuAllExists(skus, createReqVO.getProducts(), BargainProductBaseVO::getSkuId);
// 插入砍价活动
BargainActivityDO activity = BargainActivityConvert.INSTANCE.convert(createReqVO);
// TODO 营销相关属性初始化 砍价成功更新相关属性
activity.setSuccessCount(0);
// 活动总库存
activity.setStock(getSumValue(createReqVO.getProducts(), BargainProductBaseVO::getStock, Integer::sum));
activity.setStatus(CommonStatusEnum.ENABLE.getStatus());
bargainActivityMapper.insert(activity);
// 插入商品
List<BargainProductDO> productDOs = BargainActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activity);
bargainProductMapper.insertBatch(productDOs);
// 返回
return activity.getId();
if (!CollectionUtils.convertSet(skus, ProductSkuRespDTO::getId).contains(skuId)) {
throw exception(SKU_NOT_EXISTS);
}
}
private void validateProductBargainConflict(Long spuId, Long activityId) {
@Override
@Transactional(rollbackFor = Exception.class)
public Long createBargainActivity(BargainActivityBaseVO createReqVO) {
// 校验商品 SPU 是否存在是否参加的别的活动
validateBargainConflict(createReqVO.getSpuId(), null);
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(createReqVO.getSpuId()));
validateSku(createReqVO.getSkuId(), skus);
// 插入砍价活动
BargainActivityDO activityDO = BargainActivityConvert.INSTANCE.convert(createReqVO);
// TODO 营销相关属性初始化 砍价成功更新相关属性
activityDO.setSuccessCount(0);
activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
bargainActivityMapper.insert(activityDO);
// 返回
return activityDO.getId();
}
private void validateBargainConflict(Long spuId, Long activityId) {
// 校验商品 spu 是否存在
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
if (CollUtil.isEmpty(spuList)) {
@ -106,52 +103,16 @@ public class BargainActivityServiceImpl implements BargainActivityService {
throw exception(BARGAIN_ACTIVITY_STATUS_DISABLE);
}
// 校验商品冲突
validateProductBargainConflict(updateReqVO.getSpuId(), updateReqVO.getId());
validateBargainConflict(updateReqVO.getSpuId(), updateReqVO.getId());
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(updateReqVO.getSpuId()));
// 校验商品 sku 是否存在
validateProductSkuAllExists(skus, updateReqVO.getProducts(), BargainProductBaseVO::getSkuId);
validateSku(updateReqVO.getSkuId(), skus);
// 更新
BargainActivityDO updateObj = BargainActivityConvert.INSTANCE.convert(updateReqVO);
// 更新活动库存
updateObj.setStock(getSumValue(updateReqVO.getProducts(), BargainProductBaseVO::getStock, Integer::sum));
bargainActivityMapper.updateById(updateObj);
// 更新商品
updateBargainProduct(updateObj, updateReqVO.getProducts());
}
/**
* 更新砍价商品
*
* @param updateObj 更新的活动
* @param products 商品配置
*/
private void updateBargainProduct(BargainActivityDO updateObj, List<BargainProductBaseVO> 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
@ -178,7 +139,7 @@ public class BargainActivityServiceImpl implements BargainActivityService {
@Override
public BargainActivityDO getBargainActivity(Long id) {
return bargainActivityMapper.selectById(id);
return validateBargainActivityExists(id);
}
@Override
@ -186,9 +147,4 @@ public class BargainActivityServiceImpl implements BargainActivityService {
return bargainActivityMapper.selectPage(pageReqVO);
}
@Override
public List<BargainProductDO> getBargainProductsByActivityIds(Collection<Long> activityIds) {
return bargainProductMapper.selectListByActivityIds(activityIds);
}
}

View File

@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.bargain;
/**
* 商品活动记录 service
* 砍价记录 service 接口
*
* @author HUIHUI
*/

View File

@ -0,0 +1,14 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* 砍价记录 Service 实现类
*
* @author HUIHUI
*/
@Service
@Validated
public class BargainRecordServiceImpl implements BargainRecordService {
}

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCr
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
import java.util.List;
/**
* 拼团记录 Service 接口
*
@ -41,4 +43,23 @@ public interface CombinationRecordService {
*/
CombinationRecordDO getCombinationRecord(Long userId, Long orderId);
/**
* 获取拼团记录
*
* @param userId 用户 id
* @param activityId 活动 id
* @return 拼团记录列表
*/
List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
/**
* 验证组合限制数
* 校验是否满足限购要求
*
* @param count 本次购买数量
* @param sumCount 已购买数量合计
* @param activityId 活动编号
*/
void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
}

View File

@ -14,11 +14,11 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_RECORD_USER_FULL;
// TODO 芋艿等拼团记录做完完整 review
/**
@ -37,6 +37,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
private CombinationRecordMapper recordMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
// 校验拼团是否存在
CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
@ -80,6 +81,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
// 1.1 校验拼团活动
CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
@ -88,9 +90,19 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
if (recordDO != null) {
throw exception(COMBINATION_RECORD_EXISTS);
}
// 1.3 父拼团是否存在,是否已经满了
// 1.3 校验用户是否参加了其它拼团
List<CombinationRecordDO> recordDOList = recordMapper.selectListByUserIdAndStatus(reqDTO.getUserId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
if (CollUtil.isNotEmpty(recordDOList)) {
throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED);
}
// 1.4 校验当前活动是否过期
if (LocalDateTime.now().isAfter(activity.getEndTime())) {
throw exception(COMBINATION_RECORD_FAILED_TIME_END);
}
// 1.5 父拼团是否存在,是否已经满了
if (reqDTO.getHeadId() != null) {
CombinationRecordDO recordDO1 = recordMapper.selectRecordByHeadId(reqDTO.getHeadId(), reqDTO.getActivityId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
// 查询进行中的父拼团
CombinationRecordDO recordDO1 = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
if (recordDO1 == null) {
throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
}
@ -99,7 +111,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
throw exception(COMBINATION_RECORD_USER_FULL);
}
}
// TODO @puhui999应该还有一些校验后续补噶例如说一个团自己已经参与进去了不能再参与进去
// 2. 创建拼团记录
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
@ -115,6 +126,25 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
return validateCombinationRecord(userId, orderId);
}
@Override
public List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId) {
return recordMapper.selectListByUserIdAndActivityId(userId, activityId);
}
@Override
public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {
// 1.1 校验拼团活动
CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
// 校验是否达到限购总限购标准
if ((sumCount + count) > activity.getTotalLimitCount()) {
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
}
// 单次购买是否达到限购标准
if (count > activity.getSingleLimitCount()) {
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
}
}
/**
* APP 端获取开团记录
*

View File

@ -13,7 +13,6 @@ import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
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;
@ -152,8 +151,6 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
// 准备参数
CombinationActivityPageReqVO reqVO = new CombinationActivityPageReqVO();
reqVO.setName(null);
reqVO.setStartTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
reqVO.setEndTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
reqVO.setStatus(null);
// 调用

View File

@ -31,10 +31,7 @@ public interface ErrorCodeConstants {
ErrorCode ORDER_COMMENT_STATUS_NOT_FALSE = new ErrorCode(1011000020, "创建交易订单项的评价失败,订单已评价");
ErrorCode ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE = new ErrorCode(1011000021, "交易订单发货失败,订单已退款或部分退款");
ErrorCode ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000022, "交易订单发货失败,拼团未成功");
// TODO 已移除订单单独发货
ErrorCode ORDER_DELIVERY_FAILED_ITEMS_NOT_EMPTY = new ErrorCode(1011000023, "订单发货失败,请选择发货商品");
ErrorCode ORDER_DELIVERY_FAILED_ITEM_NOT_EXISTS = new ErrorCode(1011000024, "订单发货失败,所选发货商品不存在");
ErrorCode ORDER_DELIVERY_FAILED_ITEM_ALREADY_DELIVERY = new ErrorCode(1011000025, "订单发货失败,所选商品已发货");
ErrorCode ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS = new ErrorCode(1011000023, "交易订单发货失败,砍价未成功");
// ========== After Sale 模块 1011000100 ==========
ErrorCode AFTER_SALE_NOT_FOUND = new ErrorCode(1011000100, "售后单不存在");

View File

@ -29,7 +29,5 @@ public class TradeOrderDeliveryReqVO {
@NotEmpty(message = "发货物流单号不能为空")
private String logisticsNo;
// =============== 同城配送 ================
// TODO
}

View File

@ -149,9 +149,8 @@ public class AppTradeOrderController {
@PutMapping("/receive")
@Operation(summary = "确认交易订单收货")
@Parameter(name = "id", description = "交易订单编号")
public CommonResult<Boolean> receiveOrder(@RequestParam("id") Long id) {
tradeOrderService.receiveOrder(getLoginUserId(), id);
return success(true);
public CommonResult<Boolean> takeOrder(@RequestParam("id") Long id) {
return success(tradeOrderService.receiveOrder(getLoginUserId(), id));
}
@DeleteMapping("/cancel")

View File

@ -25,6 +25,12 @@ public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
return selectList(TradeOrderItemDO::getOrderId, orderIds);
}
default List<TradeOrderItemDO> selectListByOrderIdAnSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
return selectList(new LambdaQueryWrapperX<TradeOrderItemDO>()
.in(TradeOrderItemDO::getOrderId, orderIds)
.eq(TradeOrderItemDO::getSkuId, skuIds));
}
default TradeOrderItemDO selectOrderItemByIdAndUserId(Long orderItemId, Long loginUserId) {
return selectOne(new LambdaQueryWrapperX<TradeOrderItemDO>()
.eq(TradeOrderItemDO::getId, orderItemId)

View File

@ -65,9 +65,10 @@ public interface TradeOrderService {
* 会员收货交易订单
*
* @param userId 用户编号
* @param id 订单编号
* @param id 订单编号
* @return 成功/失败
*/
void receiveOrder(Long userId, Long id);
Boolean receiveOrder(Long userId, Long id);
/**
* 获得指定编号的交易订单

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
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;
@ -22,7 +23,9 @@ import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
@ -108,6 +111,9 @@ public class TradeOrderServiceImpl implements TradeOrderService {
@Resource
private CombinationRecordApi combinationRecordApi;
@Resource
private BargainRecordApi bargainRecordApi;
// =================== Order ===================
@Override
@ -173,8 +179,18 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// 拼团
if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
MemberUserRespDTO user = memberUserApi.getUser(userId);
List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
// TODO 拼团一次应该只能选择一种规格的商品
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user));
TradeOrderItemDO orderItemDO = orderItems.get(0);
if (CollUtil.isNotEmpty(recordRespDTOS)) {
List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
}
combinationRecordApi.createRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
}
// TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
@ -382,33 +398,23 @@ public class TradeOrderServiceImpl implements TradeOrderService {
public void deliveryOrder(Long userId, TradeOrderDeliveryReqVO deliveryReqVO) {
// 1.1 校验并获得交易订单可发货
TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
/* TODO
* fix: 首先需要店铺设置配送方式如 自提 配送物流-配送物流-配送-自提商家配送
* 1.如果店铺有设置配送方式用户只填写收货地址的情况下店家后台自己选择配送方式
* 2.如果店铺只支持到店自提那么下单后默认发货不需要物流
* 3.如果店铺支持 物流-配送-自提 的情况下后台不需要选择配送方式按前端用户选择的配送方式发货即可
*/
TradeOrderDO updateOrderObj = new TradeOrderDO();
// 判断发货类型
// 2.1 快递发货
if (Objects.equals(deliveryReqVO.getType(), DeliveryTypeEnum.EXPRESS.getMode())) {
// 校验快递公司
validateDeliveryExpress(deliveryReqVO);
updateOrderObj.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo());
DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
if (deliveryExpress == null) {
throw exception(EXPRESS_NOT_EXISTS);
}
if (deliveryExpress.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
throw exception(EXPRESS_STATUS_NOT_ENABLE);
}
updateOrderObj.setLogisticsId(deliveryReqVO.getLogisticsId()).setLogisticsNo(deliveryReqVO.getLogisticsNo()).setDeliveryType(DeliveryTypeEnum.EXPRESS.getMode());
}
// 2.2 用户自提
if (Objects.equals(deliveryReqVO.getType(), DeliveryTypeEnum.PICK_UP.getMode())) {
// TODO 校验自提门店是否存在
// 重置一下确保快递公司和快递单号为空
updateOrderObj.setLogisticsId(null).setLogisticsNo("");
}
// 2.3 TODO 芋艿如果无需发货需要怎么存储回复需要把 deliverType 设置为 DeliveryTypeEnum.NULL
// 2.2 无需发货
if (Objects.equals(deliveryReqVO.getType(), DeliveryTypeEnum.NULL.getMode())) {
// TODO 情况一正常走发货逻辑和用户自提有点像 不同点不需要自提门店只需要用户确认收货
// TODO 情况二用户下单付款后直接确认收货或等待用户确认收货
// 重置一下确保快递公司和快递单号为空
updateOrderObj.setLogisticsId(null).setLogisticsNo("");
updateOrderObj.setLogisticsId(null).setLogisticsNo("").setDeliveryType(DeliveryTypeEnum.NULL.getMode());
}
// 更新 TradeOrderDO 状态为已发货等待收货
@ -427,16 +433,6 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// TODO 设计lili是不是发货后才支持售后
}
private void validateDeliveryExpress(TradeOrderDeliveryReqVO deliveryReqVO) {
DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
if (deliveryExpress == null) {
throw exception(EXPRESS_NOT_EXISTS);
}
if (deliveryExpress.getStatus().equals(CommonStatusEnum.DISABLE.getStatus())) {
throw exception(EXPRESS_STATUS_NOT_ENABLE);
}
}
/**
* 校验交易订单满足被发货的条件
*
@ -462,17 +458,23 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// 订单类型拼团
if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
// 校验订单拼团是否成功
if (combinationRecordApi.isCombinationRecordSuccess(order.getUserId(), order.getId())) {
if (combinationRecordApi.validateRecordSuccess(order.getUserId(), order.getId())) {
throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS);
}
}
// TODO puhui999: 校验订单砍价是否成功
// 订单类类型砍价
if (Objects.equals(TradeOrderTypeEnum.BARGAIN.getType(), order.getType())) {
// 校验订单砍价是否成功
if (bargainRecordApi.validateRecordSuccess(order.getUserId(), order.getId())) {
throw exception(ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS);
}
}
return order;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void receiveOrder(Long userId, Long id) {
public Boolean receiveOrder(Long userId, Long id) {
// 校验并获得交易订单可收货
TradeOrderDO order = validateOrderReceivable(userId, id);
@ -487,6 +489,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
// TODO 芋艿lili 发送订单变化的消息
// TODO 芋艿lili 发送商品被购买完成的数据
return Boolean.TRUE;
}
/**