fix: 修复合并差异

This commit is contained in:
puhui999 2023-08-15 00:02:50 +08:00
parent de828e3d04
commit 5c2723c7bf
12 changed files with 107 additions and 364 deletions

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

@ -4,12 +4,12 @@ import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; 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.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.activity.BargainActivityRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
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.convert.bargain.BargainActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService; import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
@ -20,8 +20,6 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -40,7 +38,7 @@ public class BargainActivityController {
@PostMapping("/create") @PostMapping("/create")
@Operation(summary = "创建砍价活动") @Operation(summary = "创建砍价活动")
@PreAuthorize("@ss.hasPermission('promotion:bargain-activity:create')") @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)); return success(activityService.createBargainActivity(createReqVO));
} }
@ -79,14 +77,6 @@ public class BargainActivityController {
if (CollUtil.isEmpty(pageResult.getList())) { if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal())); 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))); return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO)));
} }

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.promotion.convert.bargain; package cn.iocoder.yudao.module.promotion.convert.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO; 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.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO; 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.BargainActivityDO;
@ -20,7 +20,7 @@ public interface BargainActivityConvert {
BargainActivityConvert INSTANCE = Mappers.getMapper(BargainActivityConvert.class); BargainActivityConvert INSTANCE = Mappers.getMapper(BargainActivityConvert.class);
BargainActivityDO convert(BargainActivityCreateReqVO bean); BargainActivityDO convert(BargainActivityBaseVO bean);
BargainActivityDO convert(BargainActivityUpdateReqVO bean); BargainActivityDO convert(BargainActivityUpdateReqVO bean);

View File

@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activit
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
@ -73,7 +72,7 @@ public interface CombinationActivityConvert {
@Mapping(target = "activityId", source = "activity.id"), @Mapping(target = "activityId", source = "activity.id"),
@Mapping(target = "spuId", source = "activity.spuId"), @Mapping(target = "spuId", source = "activity.spuId"),
@Mapping(target = "skuId", source = "product.skuId"), @Mapping(target = "skuId", source = "product.skuId"),
@Mapping(target = "activePrice", source = "product.activePrice"), @Mapping(target = "combinationPrice", source = "product.combinationPrice"),
@Mapping(target = "activityStartTime", source = "activity.startTime"), @Mapping(target = "activityStartTime", source = "activity.startTime"),
@Mapping(target = "activityEndTime", source = "activity.endTime") @Mapping(target = "activityEndTime", source = "activity.endTime")
}) })
@ -83,7 +82,7 @@ public interface CombinationActivityConvert {
return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus())); return CollectionUtils.convertList(products, item -> convert(activity, item).setActivityStatus(activity.getStatus()));
} }
default List<CombinationProductDO> convertList(List<CombinationProductUpdateReqVO> updateProductVOs, default List<CombinationProductDO> convertList(List<CombinationProductBaseVO> updateProductVOs,
List<CombinationProductDO> products, CombinationActivityDO activity) { List<CombinationProductDO> products, CombinationActivityDO activity) {
Map<Long, Long> productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId); Map<Long, Long> productMap = convertMap(products, CombinationProductDO::getSkuId, CombinationProductDO::getId);
return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO) return CollectionUtils.convertList(updateProductVOs, updateProductVO -> convert(activity, updateProductVO)

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.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.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityDetailRespVO;
@ -40,11 +41,14 @@ public interface SeckillActivityConvert {
PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page); PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page);
default PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page, List<SeckillProductDO> seckillProducts, List<ProductSpuRespDTO> spuList) { default PageResult<SeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> page, List<SeckillProductDO> seckillProducts, List<ProductSpuRespDTO> spuList) {
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId, c -> c); Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
PageResult<SeckillActivityRespVO> pageResult = convertPage(page); PageResult<SeckillActivityRespVO> pageResult = convertPage(page);
pageResult.getList().forEach(item -> { pageResult.getList().forEach(item -> {
item.setSpuName(spuMap.get(item.getSpuId()).getName()); MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> {
item.setPicUrl(spuMap.get(item.getSpuId()).getPicUrl()); item.setSpuName(spu.getName());
item.setPicUrl(spu.getPicUrl());
});
item.setProducts(convertList2(seckillProducts)); item.setProducts(convertList2(seckillProducts));
}); });
return pageResult; return pageResult;

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.promotion.service.bargain; package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO; 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.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO; 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.BargainActivityDO;
@ -21,7 +21,7 @@ public interface BargainActivityService {
* @param createReqVO 创建信息 * @param createReqVO 创建信息
* @return 编号 * @return 编号
*/ */
Long createBargainActivity(@Valid BargainActivityCreateReqVO createReqVO); Long createBargainActivity(@Valid BargainActivityBaseVO createReqVO);
/** /**
* 更新砍价活动 * 更新砍价活动

View File

@ -10,7 +10,7 @@ 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.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO; 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.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO; 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.convert.bargain.BargainActivityConvert;
@ -37,7 +37,8 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
*/ */
@Service @Service
@Validated @Validated
public class BargainServiceImpl implements BargainActivityService, BargainRecordService { public class BargainActivityServiceImpl implements BargainActivityService {
@Resource @Resource
private BargainActivityMapper bargainActivityMapper; private BargainActivityMapper bargainActivityMapper;
@ -57,7 +58,7 @@ public class BargainServiceImpl implements BargainActivityService, BargainRecord
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createBargainActivity(BargainActivityCreateReqVO createReqVO) { public Long createBargainActivity(BargainActivityBaseVO createReqVO) {
// 校验商品 SPU 是否存在是否参加的别的活动 // 校验商品 SPU 是否存在是否参加的别的活动
validateBargainConflict(createReqVO.getSpuId(), null); validateBargainConflict(createReqVO.getSpuId(), null);
// 获取所选 spu下的所有 sku // 获取所选 spu下的所有 sku

View File

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

@ -14,11 +14,11 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINATION_RECORD_USER_FULL;
// TODO 芋艿等拼团记录做完完整 review // TODO 芋艿等拼团记录做完完整 review
/** /**
@ -37,6 +37,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
private CombinationRecordMapper recordMapper; private CombinationRecordMapper recordMapper;
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) { public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
// 校验拼团是否存在 // 校验拼团是否存在
CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId()); CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
@ -80,6 +81,7 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) { public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
// 1.1 校验拼团活动 // 1.1 校验拼团活动
CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId()); CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
@ -88,9 +90,19 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
if (recordDO != null) { if (recordDO != null) {
throw exception(COMBINATION_RECORD_EXISTS); 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) { 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) { if (recordDO1 == null) {
throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS); throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
} }
@ -99,7 +111,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
throw exception(COMBINATION_RECORD_USER_FULL); throw exception(COMBINATION_RECORD_USER_FULL);
} }
} }
// TODO @puhui999应该还有一些校验后续补噶例如说一个团自己已经参与进去了不能再参与进去
// 2. 创建拼团记录 // 2. 创建拼团记录
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO); CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
@ -115,6 +126,25 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
return validateCombinationRecord(userId, orderId); 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 端获取开团记录 * APP 端获取开团记录
* *

View File

@ -1,319 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.combination;
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.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordUpdateStatusReqDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product.CombinationProductUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationActivityMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationProductMapper;
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
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.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 CombinationServiceImpl implements CombinationActivityService, CombinationRecordService {
@Resource
private CombinationActivityMapper combinationActivityMapper;
@Resource
private CombinationRecordMapper recordMapper;
@Resource
private CombinationProductMapper combinationProductMapper;
@Resource
private ProductSpuApi productSpuApi;
@Resource
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(skus, createReqVO.getProducts(), CombinationProductCreateReqVO::getSkuId);
// 插入拼团活动
CombinationActivityDO activityDO = CombinationActivityConvert.INSTANCE.convert(createReqVO);
// TODO 营销相关属性初始化 拼团成功更新相关属性
activityDO.setTotalNum(0);
activityDO.setSuccessNum(0);
activityDO.setOrderUserCount(0);
activityDO.setVirtualGroup(0);
activityDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
combinationActivityMapper.insert(activityDO);
// 插入商品
List<CombinationProductDO> productDOs = CombinationActivityConvert.INSTANCE.convertList(createReqVO.getProducts(), activityDO);
combinationProductMapper.insertBatch(productDOs);
// 返回
return activityDO.getId();
}
private void validateProductCombinationConflict(Long spuId, Long activityId) {
// 校验商品 spu 是否存在
List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(CollUtil.newArrayList(spuId));
if (CollUtil.isEmpty(spuList)) {
throw exception(SPU_NOT_EXISTS);
}
// 查询所有开启的拼团活动
List<CombinationActivityDO> activityDOs = combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus());
// 更新时排除自己
if (activityId != null) {
activityDOs.removeIf(item -> ObjectUtil.equal(item.getId(), activityId));
}
// 过滤出所有 spuIds 有交集的活动
List<CombinationActivityDO> doList = CollectionUtils.convertList(activityDOs, c -> c, s -> ObjectUtil.equal(s.getId(), spuId));
if (CollUtil.isNotEmpty(doList)) {
throw exception(COMBINATION_ACTIVITY_SPU_CONFLICTS);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationActivity(CombinationActivityUpdateReqVO updateReqVO) {
// 校验存在
CombinationActivityDO activityDO = validateCombinationActivityExists(updateReqVO.getId());
// 校验状态
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
}
// 校验商品冲突
validateProductCombinationConflict(updateReqVO.getSpuId(), updateReqVO.getId());
// 获取所选 spu下的所有 sku
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(CollectionUtil.newArrayList(updateReqVO.getSpuId()));
// 校验商品 sku 是否存在
validateProductSkuAllExists(skus, updateReqVO.getProducts(), CombinationProductUpdateReqVO::getSkuId);
// 更新
CombinationActivityDO updateObj = CombinationActivityConvert.INSTANCE.convert(updateReqVO);
combinationActivityMapper.updateById(updateObj);
// 更新商品
updateCombinationProduct(updateObj, updateReqVO.getProducts());
}
/**
* 更新拼团商品
*
* @param activity 拼团活动
* @param products 该活动的最新商品配置
*/
private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductUpdateReqVO> products) {
// 第一步对比新老数据获得添加修改删除的列表
List<CombinationProductDO> newList = CombinationActivityConvert.INSTANCE.convertList(products, activity);
List<CombinationProductDO> oldList = combinationProductMapper.selectListByActivityIds(CollUtil.newArrayList(activity.getId()));
List<List<CombinationProductDO>> diffList = CollectionUtils.diffList(oldList, newList, (oldVal, newVal) -> {
boolean same = ObjectUtil.equal(oldVal.getSkuId(), newVal.getSkuId());
if (same) {
newVal.setId(oldVal.getId());
}
return same;
});
// 第二步批量添加修改删除
if (CollUtil.isNotEmpty(diffList.get(0))) {
combinationProductMapper.insertBatch(diffList.get(0));
}
if (CollUtil.isNotEmpty(diffList.get(1))) {
combinationProductMapper.updateBatch(diffList.get(1));
}
if (CollUtil.isNotEmpty(diffList.get(2))) {
combinationProductMapper.deleteBatchIds(CollectionUtils.convertList(diffList.get(2), CombinationProductDO::getId));
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteCombinationActivity(Long id) {
// 校验存在
CombinationActivityDO activityDO = validateCombinationActivityExists(id);
// 校验状态
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
throw exception(COMBINATION_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
}
// 删除
combinationActivityMapper.deleteById(id);
}
private CombinationActivityDO validateCombinationActivityExists(Long id) {
CombinationActivityDO activityDO = combinationActivityMapper.selectById(id);
if (activityDO == null) {
throw exception(COMBINATION_ACTIVITY_NOT_EXISTS);
}
return activityDO;
}
@Override
public CombinationActivityDO getCombinationActivity(Long id) {
return validateCombinationActivityExists(id);
}
@Override
public List<CombinationActivityDO> getCombinationActivityList(Collection<Long> ids) {
return combinationActivityMapper.selectBatchIds(ids);
}
@Override
public PageResult<CombinationActivityDO> getCombinationActivityPage(CombinationActivityPageReqVO pageReqVO) {
return combinationActivityMapper.selectPage(pageReqVO);
}
@Override
public List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> ids) {
return combinationProductMapper.selectListByActivityIds(ids);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
// 校验拼团是否存在
CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
// 更新状态
recordDO.setStatus(reqDTO.getStatus());
recordMapper.updateById(recordDO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationRecordStatusAndStartTimeByUserIdAndOrderId(CombinationRecordUpdateStatusReqDTO reqDTO) {
CombinationRecordDO recordDO = validateCombinationRecord(reqDTO.getUserId(), reqDTO.getOrderId());
// 更新状态
recordDO.setStatus(reqDTO.getStatus());
// 更新开始时间
recordDO.setStartTime(reqDTO.getStartTime());
recordMapper.updateById(recordDO);
// 更新拼团参入人数
List<CombinationRecordDO> recordDOs = recordMapper.selectListByHeadIdAndStatus(recordDO.getHeadId(), reqDTO.getStatus());
if (CollUtil.isNotEmpty(recordDOs)) {
recordDOs.forEach(item -> {
item.setUserCount(recordDOs.size());
// 校验拼团是否满足要求
if (ObjectUtil.equal(recordDOs.size(), recordDO.getUserSize())) {
item.setStatus(CombinationRecordStatusEnum.SUCCESS.getStatus());
}
});
}
recordMapper.updateBatch(recordDOs);
}
private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
// 校验拼团是否存在
CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(userId, orderId);
if (recordDO == null) {
throw exception(COMBINATION_RECORD_NOT_EXISTS);
}
return recordDO;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
// 1.1 校验拼团活动
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
// 1.2 需要校验下他当前是不是已经参加了该拼团
CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(reqDTO.getUserId(), reqDTO.getOrderId());
if (recordDO != null) {
throw exception(COMBINATION_RECORD_EXISTS);
}
// 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.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
if (recordDO1 == null) {
throw exception(COMBINATION_RECORD_HEAD_NOT_EXISTS);
}
// 校验拼团是否满足要求
if (ObjectUtil.equal(recordDO1.getUserCount(), recordDO1.getUserSize())) {
throw exception(COMBINATION_RECORD_USER_FULL);
}
}
// 2. 创建拼团记录
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
record.setVirtualGroup(false);
// TODO @puhui999过期时间应该是 Date
record.setExpireTime(activity.getLimitDuration());
record.setUserSize(activity.getUserSize());
recordMapper.insert(record);
}
@Override
public CombinationRecordDO getCombinationRecord(Long userId, Long orderId) {
return validateCombinationRecord(userId, orderId);
}
/**
* APP 端获取开团记录
*
* @return 开团记录
*/
public List<CombinationRecordDO> getRecordListByStatus(Integer status) {
return recordMapper.selectListByStatus(status);
}
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 = 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);
}
}
}

View File

@ -23,15 +23,15 @@ import static org.junit.jupiter.api.Assertions.*;
// TODO 芋艿等完成后在补全单测 // TODO 芋艿等完成后在补全单测
/** /**
* {@link CombinationServiceImpl} 的单元测试类 * {@link CombinationActivityServiceImpl} 的单元测试类
* *
* @author HUIHUI * @author HUIHUI
*/ */
@Import(CombinationServiceImpl.class) @Import(CombinationActivityServiceImpl.class)
public class CombinationActivityServiceImplTest extends BaseDbUnitTest { public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
@Resource @Resource
private CombinationServiceImpl combinationActivityService; private CombinationActivityServiceImpl combinationActivityService;
@Resource @Resource
private CombinationActivityMapper combinationActivityMapper; private CombinationActivityMapper combinationActivityMapper;
@ -111,8 +111,8 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
o.setStartTime(null); o.setStartTime(null);
o.setEndTime(null); o.setEndTime(null);
o.setUserSize(null); o.setUserSize(null);
o.setTotalNum(null); o.setTotalCount(null);
o.setSuccessNum(null); o.setSuccessCount(null);
o.setOrderUserCount(null); o.setOrderUserCount(null);
o.setVirtualGroup(null); o.setVirtualGroup(null);
o.setStatus(null); o.setStatus(null);
@ -135,9 +135,9 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
// 测试 userSize 不匹配 // 测试 userSize 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setUserSize(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setUserSize(null)));
// 测试 totalNum 不匹配 // 测试 totalNum 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalNum(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalCount(null)));
// 测试 successNum 不匹配 // 测试 successNum 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSuccessNum(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSuccessCount(null)));
// 测试 orderUserCount 不匹配 // 测试 orderUserCount 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setOrderUserCount(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setOrderUserCount(null)));
// 测试 virtualGroup 不匹配 // 测试 virtualGroup 不匹配
@ -173,8 +173,8 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
o.setStartTime(null); o.setStartTime(null);
o.setEndTime(null); o.setEndTime(null);
o.setUserSize(null); o.setUserSize(null);
o.setTotalNum(null); o.setTotalCount(null);
o.setSuccessNum(null); o.setSuccessCount(null);
o.setOrderUserCount(null); o.setOrderUserCount(null);
o.setVirtualGroup(null); o.setVirtualGroup(null);
o.setStatus(null); o.setStatus(null);
@ -197,9 +197,9 @@ public class CombinationActivityServiceImplTest extends BaseDbUnitTest {
// 测试 userSize 不匹配 // 测试 userSize 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setUserSize(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setUserSize(null)));
// 测试 totalNum 不匹配 // 测试 totalNum 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalNum(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setTotalCount(null)));
// 测试 successNum 不匹配 // 测试 successNum 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSuccessNum(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setSuccessCount(null)));
// 测试 orderUserCount 不匹配 // 测试 orderUserCount 不匹配
combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setOrderUserCount(null))); combinationActivityMapper.insert(cloneIgnoreId(dbCombinationActivity, o -> o.setOrderUserCount(null)));
// 测试 virtualGroup 不匹配 // 测试 virtualGroup 不匹配