!643 订单:完善拼团活动和一些 TODO
Merge pull request !643 from puhui999/feature/mall_product
This commit is contained in:
commit
4f7d6b4959
|
@ -97,4 +97,44 @@ public class LocalDateTimeUtils {
|
|||
LocalDateTime.of(nowDate, startTime2), LocalDateTime.of(nowDate, endTime2));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建日期时间 TODO 后面有需要的话再继续扩展
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public static class BuilderDateTime {
|
||||
|
||||
/**
|
||||
* 日期;2023-10-01
|
||||
*/
|
||||
private String localDate;
|
||||
/**
|
||||
* 时间;10:01:00
|
||||
*/
|
||||
private String localTime;
|
||||
|
||||
public BuilderDateTime() {
|
||||
}
|
||||
|
||||
public BuilderDateTime withDate(String date) {
|
||||
this.localDate = date;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuilderDateTime withDate(LocalDateTime date) {
|
||||
this.localDate = LocalDateTimeUtil.format(date, "yyyy-MM-dd");
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuilderDateTime withTime(String time) {
|
||||
this.localTime = time;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LocalDateTime build() {
|
||||
return LocalDateTimeUtil.parse(this.localDate + " " + this.localTime, "yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,13 +20,4 @@ public interface BargainRecordApi {
|
|||
*/
|
||||
void createBargainRecord(@Valid BargainRecordCreateReqDTO reqDTO);
|
||||
|
||||
/**
|
||||
* 查询砍价是否成功
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param orderId 订单编号
|
||||
* @return 砍价是否成功
|
||||
*/
|
||||
boolean isBargainRecordSuccess(Long userId, Long orderId);
|
||||
|
||||
}
|
||||
|
|
|
@ -7,14 +7,4 @@ package cn.iocoder.yudao.module.promotion.api.combination;
|
|||
*/
|
||||
public interface CombinationActivityApi {
|
||||
|
||||
/**
|
||||
* 校验是否满足拼团条件
|
||||
*
|
||||
* @param activityId 活动编号
|
||||
* @param userId 用户编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,16 @@ import java.time.LocalDateTime;
|
|||
*/
|
||||
public interface CombinationRecordApi {
|
||||
|
||||
/**
|
||||
* 校验是否满足拼团条件
|
||||
*
|
||||
* @param activityId 活动编号
|
||||
* @param userId 用户编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count);
|
||||
|
||||
/**
|
||||
* 创建开团记录
|
||||
*
|
||||
|
|
|
@ -28,6 +28,11 @@ public class CombinationRecordCreateReqDTO {
|
|||
*/
|
||||
@NotNull(message = "sku 编号不能为空")
|
||||
private Long skuId;
|
||||
/**
|
||||
* 购买的商品数量
|
||||
*/
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package cn.iocoder.yudao.module.promotion.api.seckill;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 秒杀活动 API 接口
|
||||
*
|
||||
|
@ -16,4 +21,13 @@ public interface SeckillActivityApi {
|
|||
*/
|
||||
void updateSeckillStock(Long id, Long skuId, Integer count);
|
||||
|
||||
/**
|
||||
* 获取秒杀活动商品信息
|
||||
*
|
||||
* @param id 活动编号
|
||||
* @param skuIds sku 编号
|
||||
* @return 秒杀活动商品信息列表
|
||||
*/
|
||||
List<SeckillActivityProductRespDTO> getSeckillActivityProductList(Long id, Collection<Long> skuIds);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package cn.iocoder.yudao.module.promotion.api.seckill.dto;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 秒杀活动商品 Response DTO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class SeckillActivityProductRespDTO {
|
||||
|
||||
/**
|
||||
* 秒杀参与商品编号
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 秒杀活动 id
|
||||
*
|
||||
* 关联 SeckillActivityDO#getId()
|
||||
*/
|
||||
private Long activityId;
|
||||
/**
|
||||
* 秒杀时段 id
|
||||
*
|
||||
* 关联 SeckillConfigDO#getId()
|
||||
*/
|
||||
private List<Long> configIds;
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
*/
|
||||
private Long spuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*/
|
||||
private Long skuId;
|
||||
/**
|
||||
* 秒杀金额,单位:分
|
||||
*/
|
||||
private Integer seckillPrice;
|
||||
/**
|
||||
* 秒杀库存
|
||||
*/
|
||||
private Integer stock;
|
||||
|
||||
/**
|
||||
* 秒杀商品状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum 对应的类}
|
||||
*/
|
||||
private Integer activityStatus;
|
||||
/**
|
||||
* 活动开始时间点
|
||||
*/
|
||||
private LocalDateTime activityStartTime;
|
||||
/**
|
||||
* 活动结束时间点
|
||||
*/
|
||||
private LocalDateTime activityEndTime;
|
||||
|
||||
}
|
|
@ -75,9 +75,11 @@ public interface ErrorCodeConstants {
|
|||
ErrorCode COMBINATION_RECORD_HEAD_NOT_EXISTS = new ErrorCode(1_013_011_002, "拼团失败,父拼团不存在");
|
||||
ErrorCode COMBINATION_RECORD_USER_FULL = new ErrorCode(1_013_011_003, "拼团失败,拼团人数已满");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_HAVE_JOINED = new ErrorCode(1_013_011_004, "拼团失败,已参与其它拼团");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1_013_011_005, "拼团失败,活动已经结束");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_006, "拼团失败,原因:单次限购超出");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_007, "拼团失败,原因:超出总购买次数");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_TIME_NOT_START = new ErrorCode(1_013_011_005, "拼团失败,活动未开始");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_TIME_END = new ErrorCode(1_013_011_006, "拼团失败,活动已经结束");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_007, "拼团失败,原因:单次限购超出");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED = new ErrorCode(1_013_011_008, "拼团失败,原因:超出总购买次数");
|
||||
ErrorCode COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID = new ErrorCode(1_013_011_009, "拼团失败,原因:存在未支付订单,请先支付");
|
||||
|
||||
// ========== 砍价活动 1-013-012-000 ==========
|
||||
ErrorCode BARGAIN_ACTIVITY_NOT_EXISTS = new ErrorCode(1_013_012_000, "砍价活动不存在");
|
||||
|
|
|
@ -16,9 +16,4 @@ public class BargainRecordApiImpl implements BargainRecordApi {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBargainRecordSuccess(Long userId, Long orderId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package cn.iocoder.yudao.module.promotion.api.combination;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 拼团活动 Api 接口实现类
|
||||
*
|
||||
|
@ -13,12 +10,4 @@ import javax.annotation.Resource;
|
|||
@Service
|
||||
public class CombinationActivityApiImpl implements CombinationActivityApi {
|
||||
|
||||
@Resource
|
||||
private CombinationActivityService activityService;
|
||||
|
||||
@Override
|
||||
public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
|
||||
activityService.validateCombination(activityId, userId, skuId, count);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
|
|||
@Resource
|
||||
private CombinationRecordService recordService;
|
||||
|
||||
@Override
|
||||
public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) {
|
||||
recordService.validateCombinationRecord(activityId, userId, skuId, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
recordService.createCombinationRecord(reqDTO);
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package cn.iocoder.yudao.module.promotion.api.seckill;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
|
||||
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 秒杀活动接口 Api 接口实现类
|
||||
|
@ -21,4 +25,9 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
|
|||
activityService.updateSeckillStock(id, skuId, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SeckillActivityProductRespDTO> getSeckillActivityProductList(Long id, Collection<Long> skuIds) {
|
||||
return SeckillActivityConvert.INSTANCE.convertList4(activityService.getSeckillActivityProductList(id, skuIds));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,8 +97,8 @@ public interface CombinationActivityConvert {
|
|||
default CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO,
|
||||
CombinationActivityDO activity, MemberUserRespDTO user,
|
||||
ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
|
||||
// TODO @puhui999:订单付款后需要设置开始时间和结束时间;
|
||||
return convert(reqDTO)
|
||||
.setCount(reqDTO.getCount())
|
||||
.setVirtualGroup(false)
|
||||
.setExpireTime(activity.getStartTime().plusHours(activity.getLimitDuration()))
|
||||
.setUserSize(activity.getUserSize())
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
|
||||
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
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.framework.common.util.date.LocalDateTimeUtils;
|
||||
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
|
||||
import cn.iocoder.yudao.module.product.enums.DictTypeConstants;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
|
||||
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.SeckillActivityRespVO;
|
||||
|
@ -128,11 +129,16 @@ public interface SeckillActivityConvert {
|
|||
default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
|
||||
return convert2(seckillActivity)
|
||||
.setProducts(convertList1(products))
|
||||
// TODO @puhui999:要不要在里面 default 一个方法,处理这个事件;简洁一点;
|
||||
.setStartTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getStartTime(), "yyyy-MM-dd") + " " + filteredConfig.getStartTime(),
|
||||
"yyyy-MM-dd HH:mm:ss")) // 活动开始日期和时段结合
|
||||
.setEndTime(LocalDateTimeUtil.parse(LocalDateTimeUtil.format(seckillActivity.getEndTime(), "yyyy-MM-dd") + " " + filteredConfig.getEndTime(),
|
||||
"yyyy-MM-dd HH:mm:ss")); // 活动结束日期和时段结合
|
||||
.setStartTime(new LocalDateTimeUtils.BuilderDateTime()
|
||||
.withDate(seckillActivity.getStartTime())
|
||||
.withTime(filteredConfig.getStartTime())
|
||||
.build())// 活动开始日期和时段结合
|
||||
.setEndTime(new LocalDateTimeUtils.BuilderDateTime()
|
||||
.withDate(seckillActivity.getEndTime())
|
||||
.withTime(filteredConfig.getEndTime())
|
||||
.build()); // 活动结束日期和时段结合
|
||||
}
|
||||
|
||||
List<SeckillActivityProductRespDTO> convertList4(List<SeckillProductDO> seckillActivityProductList);
|
||||
|
||||
}
|
||||
|
|
|
@ -62,6 +62,10 @@ public class CombinationRecordDO extends BaseDO {
|
|||
* SKU 编号
|
||||
*/
|
||||
private Long skuId;
|
||||
/**
|
||||
* 购买的商品数量
|
||||
*/
|
||||
private Integer count;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
|
|
|
@ -20,6 +20,10 @@ public interface CombinationRecordMapper extends BaseMapperX<CombinationRecordDO
|
|||
CombinationRecordDO::getOrderId, orderId);
|
||||
}
|
||||
|
||||
default List<CombinationRecordDO> selectListByUserId(Long userId) {
|
||||
return selectList(CombinationRecordDO::getUserId, userId);
|
||||
}
|
||||
|
||||
default List<CombinationRecordDO> selectListByUserIdAndStatus(Long userId, Integer status) {
|
||||
return selectList(new LambdaQueryWrapperX<CombinationRecordDO>()
|
||||
.eq(CombinationRecordDO::getUserId, userId)
|
||||
|
|
|
@ -116,10 +116,10 @@ public class BargainActivityServiceImpl implements BargainActivityService {
|
|||
public void deleteBargainActivity(Long id) {
|
||||
// 校验存在
|
||||
BargainActivityDO activityDO = validateBargainActivityExists(id);
|
||||
// 校验状态 TODO puhui: 测试完成后需要恢复校验
|
||||
//if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
|
||||
// throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
|
||||
//}
|
||||
// 校验状态
|
||||
if (ObjectUtil.equal(activityDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
|
||||
throw exception(BARGAIN_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END);
|
||||
}
|
||||
|
||||
// 删除
|
||||
bargainActivityMapper.deleteById(id);
|
||||
|
|
|
@ -84,17 +84,6 @@ public interface CombinationActivityService {
|
|||
*/
|
||||
List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
|
||||
|
||||
/**
|
||||
* 校验是否满足拼团条件
|
||||
* 如果不满足,会抛出异常
|
||||
*
|
||||
* @param activityId 活动编号
|
||||
* @param userId 用户编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
|
||||
|
||||
/**
|
||||
* 获取正在进行的活动分页数据
|
||||
*
|
||||
|
|
|
@ -17,12 +17,8 @@ import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.product
|
|||
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.enums.combination.CombinationRecordStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
@ -33,7 +29,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
|
||||
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.*;
|
||||
|
@ -53,16 +50,10 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
|||
@Resource
|
||||
private CombinationProductMapper combinationProductMapper;
|
||||
|
||||
@Resource
|
||||
@Lazy // TODO @puhui999:我感觉 validateCombination 可以挪到 CombinationRecordServiceImpl 中,因为它更偏向能不能创建拼团记录;
|
||||
private CombinationRecordService combinationRecordService;
|
||||
|
||||
@Resource
|
||||
private ProductSpuApi productSpuApi;
|
||||
@Resource
|
||||
private ProductSkuApi productSkuApi;
|
||||
@Resource
|
||||
private TradeOrderApi tradeOrderApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -215,36 +206,6 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
|
|||
return combinationProductMapper.selectListByActivityIds(activityIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
|
||||
// 1.1 校验拼团活动是否存在
|
||||
CombinationActivityDO activity = validateCombinationActivityExists(activityId);
|
||||
// 1.2 校验活动是否开启
|
||||
if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
|
||||
}
|
||||
// 1.3 校验是否超出单次限购数量
|
||||
if (count > activity.getSingleLimitCount()) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
|
||||
// 2. 校验是否超出总限购数量
|
||||
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId);
|
||||
if (CollUtil.isEmpty(recordList)) {
|
||||
return;
|
||||
}
|
||||
// 过滤出拼团成功的
|
||||
// TODO @puhui999:count 要不存一个在 record 里?
|
||||
List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
|
||||
Integer countSum = tradeOrderApi.getOrderItemCountSumByOrderIdAndSkuId(convertList(recordList,
|
||||
CombinationRecordDO::getOrderId,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
|
||||
if (activity.getTotalLimitCount() < countSum) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CombinationActivityDO> getCombinationActivityListByCount(Integer count) {
|
||||
return combinationActivityMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus(), count);
|
||||
|
|
|
@ -22,6 +22,17 @@ public interface CombinationRecordService {
|
|||
*/
|
||||
void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
|
||||
|
||||
/**
|
||||
* 校验是否满足拼团条件
|
||||
* 如果不满足,会抛出异常
|
||||
*
|
||||
* @param activityId 活动编号
|
||||
* @param userId 用户编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count);
|
||||
|
||||
/**
|
||||
* 创建拼团记录
|
||||
*
|
||||
|
|
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.combination;
|
|||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
|
||||
|
@ -14,6 +15,8 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationA
|
|||
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationRecordDO;
|
||||
import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecordMapper;
|
||||
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
@ -24,6 +27,7 @@ import java.time.LocalDateTime;
|
|||
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.*;
|
||||
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
|
||||
|
||||
// TODO 芋艿:等拼团记录做完,完整 review 下
|
||||
|
@ -51,6 +55,8 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
|||
@Resource
|
||||
@Lazy
|
||||
private ProductSkuApi productSkuApi;
|
||||
@Resource
|
||||
private TradeOrderApi tradeOrderApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
|
@ -96,30 +102,77 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
|||
return recordDO;
|
||||
}
|
||||
|
||||
// TODO @puhui999:有一个应该在创建那要做下;就是当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
|
||||
@Override
|
||||
public void validateCombinationRecord(Long activityId, Long userId, Long skuId, Integer count) {
|
||||
// 1.1 校验拼团活动是否存在
|
||||
CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
|
||||
// 1.2 校验活动是否开启
|
||||
if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
|
||||
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
|
||||
}
|
||||
// 2 校验是否超出单次限购数量
|
||||
if (count > activity.getSingleLimitCount()) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
// 3、校验是否有拼团记录
|
||||
List<CombinationRecordDO> recordList = getRecordListByUserIdAndActivityId(userId, activityId);
|
||||
if (CollUtil.isEmpty(recordList)) {
|
||||
return;
|
||||
}
|
||||
// 4、校验是否超出总限购数量
|
||||
Integer sumValue = getSumValue(convertList(recordList, CombinationRecordDO::getCount,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), i -> i, Integer::sum);
|
||||
if ((sumValue + count) > activity.getTotalLimitCount()) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
// 5、校验拼团记录是否存在未支付的订单(如果存在未支付的订单则不允许发起新的拼团)
|
||||
CombinationRecordDO record = findFirst(recordList, item -> ObjectUtil.equals(item.getStatus(), null));
|
||||
if (record == null) {
|
||||
return;
|
||||
}
|
||||
// 5.1、查询关联的订单是否已经支付
|
||||
// 当前 activityId 已经有未支付的订单,不允许在发起新的;要么支付,要么去掉先;
|
||||
Integer orderStatus = tradeOrderApi.getOrderStatus(record.getOrderId());
|
||||
if (ObjectUtil.equal(orderStatus, TradeOrderStatusEnum.UNPAID.getStatus())) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_ORDER_STATUS_UNPAID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createCombinationRecord(CombinationRecordCreateReqDTO reqDTO) {
|
||||
// 1.1 校验拼团活动
|
||||
|
||||
// 1.1、 校验拼团活动
|
||||
CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(reqDTO.getActivityId());
|
||||
// 1.2 需要校验下,他当前是不是已经参加了该拼团;
|
||||
// TODO @puhui999:拼团应该可以重复参加;应该去校验总共的上限哈,就是 activity.totalLimitCount
|
||||
CombinationRecordDO recordDO = recordMapper.selectByUserIdAndOrderId(reqDTO.getUserId(), reqDTO.getOrderId());
|
||||
if (recordDO != null) {
|
||||
throw exception(COMBINATION_RECORD_EXISTS);
|
||||
// 1.2 校验是否超出单次限购数量
|
||||
if (reqDTO.getCount() > activity.getSingleLimitCount()) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
// 1.3 校验用户是否参加了其它拼团
|
||||
// 1.3、校验是否有拼团记录
|
||||
List<CombinationRecordDO> records = getRecordListByUserIdAndActivityId(reqDTO.getUserId(), reqDTO.getActivityId());
|
||||
if (CollUtil.isEmpty(records)) {
|
||||
return;
|
||||
}
|
||||
// 1.4、校验是否超出总限购数量
|
||||
Integer sumValue = getSumValue(convertList(records, CombinationRecordDO::getCount,
|
||||
item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), i -> i, Integer::sum);
|
||||
if ((sumValue + reqDTO.getCount()) > activity.getTotalLimitCount()) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
|
||||
}
|
||||
// 2、 校验用户是否参加了其它拼团
|
||||
List<CombinationRecordDO> recordDOList = recordMapper.selectListByUserIdAndStatus(reqDTO.getUserId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
|
||||
if (CollUtil.isNotEmpty(recordDOList)) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_HAVE_JOINED);
|
||||
}
|
||||
// TODO @puhui999:有个开始时间未校验
|
||||
// 1.4 校验当前活动是否过期
|
||||
// 3、 校验活动是否开启
|
||||
if (LocalDateTime.now().isAfter(activity.getStartTime())) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TIME_NOT_START);
|
||||
}
|
||||
// 4、 校验当前活动是否过期
|
||||
if (LocalDateTime.now().isAfter(activity.getEndTime())) {
|
||||
throw exception(COMBINATION_RECORD_FAILED_TIME_END);
|
||||
}
|
||||
// 1.5 父拼团是否存在,是否已经满了
|
||||
// 5、 父拼团是否存在,是否已经满了
|
||||
if (reqDTO.getHeadId() != null) {
|
||||
// 查询进行中的父拼团
|
||||
CombinationRecordDO record = recordMapper.selectOneByHeadId(reqDTO.getHeadId(), CombinationRecordStatusEnum.IN_PROGRESS.getStatus());
|
||||
|
@ -132,8 +185,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO @puhui999:单次限购
|
||||
|
||||
// 2. 创建拼团记录
|
||||
MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
|
||||
ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
|
||||
|
|
|
@ -37,9 +37,9 @@ public interface SeckillActivityService {
|
|||
/**
|
||||
* 更新秒杀库存
|
||||
*
|
||||
* @param id 活动编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
* @param id 活动编号
|
||||
* @param skuId sku 编号
|
||||
* @param count 数量
|
||||
*/
|
||||
void updateSeckillStock(Long id, Long skuId, Integer count);
|
||||
|
||||
|
@ -114,4 +114,13 @@ public interface SeckillActivityService {
|
|||
*/
|
||||
PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 获取秒杀活动商品信息
|
||||
*
|
||||
* @param id 活动编号
|
||||
* @param skuIds sku 编号
|
||||
* @return 秒杀活动商品信息列表
|
||||
*/
|
||||
List<SeckillProductDO> getSeckillActivityProductList(Long id, Collection<Long> skuIds);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package cn.iocoder.yudao.module.promotion.service.seckill;
|
||||
|
||||
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;
|
||||
|
@ -278,4 +279,18 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
|
|||
return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SeckillProductDO> getSeckillActivityProductList(Long id, Collection<Long> skuIds) {
|
||||
// 1、校验秒杀活动是否存在
|
||||
validateSeckillActivityExists(id);
|
||||
// 2、校验活动商品是否存在
|
||||
List<SeckillProductDO> productList = filterList(seckillProductMapper.selectListByActivityId(id),
|
||||
item -> skuIds.contains(item.getSkuId()));
|
||||
if (CollectionUtil.isEmpty(productList)) {
|
||||
throw exception(SKU_NOT_EXISTS);
|
||||
}
|
||||
|
||||
return productList;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package cn.iocoder.yudao.module.trade.api.order;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 订单 API 接口
|
||||
*
|
||||
|
@ -10,21 +8,11 @@ import java.util.Collection;
|
|||
public interface TradeOrderApi {
|
||||
|
||||
/**
|
||||
* 验证订单
|
||||
* 获取订单状态
|
||||
*
|
||||
* @param userId 用户 id
|
||||
* @param orderItemId 订单项 id
|
||||
* @return 校验通过返回订单 id
|
||||
* @param id 订单编号
|
||||
* @return 订单状态
|
||||
*/
|
||||
Long validateOrder(Long userId, Long orderItemId);
|
||||
|
||||
/**
|
||||
* 获取订单项商品购买数量总和
|
||||
*
|
||||
* @param orderIds 订单编号
|
||||
* @param skuIds sku 编号
|
||||
* @return 订单项商品购买数量总和
|
||||
*/
|
||||
Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
|
||||
Integer getOrderStatus(Long id);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package cn.iocoder.yudao.module.trade.api.order;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_ITEM_NOT_FOUND;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
|
||||
|
||||
/**
|
||||
* 订单 API 接口实现类
|
||||
|
@ -24,18 +23,12 @@ public class TradeOrderApiImpl implements TradeOrderApi {
|
|||
private TradeOrderQueryService tradeOrderQueryService;
|
||||
|
||||
@Override
|
||||
public Long validateOrder(Long userId, Long orderItemId) {
|
||||
// 校验订单项,订单项存在订单就存在
|
||||
TradeOrderItemDO item = tradeOrderQueryService.getOrderItem(userId, orderItemId);
|
||||
if (item == null) {
|
||||
throw exception(ORDER_ITEM_NOT_FOUND);
|
||||
public Integer getOrderStatus(Long id) {
|
||||
TradeOrderDO order = tradeOrderQueryService.getOrder(id);
|
||||
if (order == null) {
|
||||
throw exception(ORDER_NOT_FOUND);
|
||||
}
|
||||
return item.getOrderId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
|
||||
return tradeOrderQueryService.getOrderItemCountSumByOrderIdAndSkuId(orderIds, skuIds);
|
||||
return order.getStatus();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.List;
|
|||
|
||||
@Schema(description = "用户 App - 交易订单结算 Request VO")
|
||||
@Data
|
||||
@Valid
|
||||
public class AppTradeOrderSettlementReqVO {
|
||||
|
||||
@Schema(description = "商品项数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
|
@ -62,7 +63,16 @@ public class AppTradeOrderSettlementReqVO {
|
|||
@Schema(description = "砍价活动编号", example = "123")
|
||||
private Long bargainActivityId;
|
||||
|
||||
// TODO @puhui999:可以写个参数校验,如果 seckillActivityId 或 combinationActivityId 或 combinationHeadId 的情况,items 应该只有一个
|
||||
@AssertTrue(message = "活动商品每次只能购买一种规格")
|
||||
@JsonIgnore
|
||||
public boolean isValidActivityItems() {
|
||||
// 校验是否是活动订单
|
||||
if (seckillActivityId == null && combinationActivityId == null && combinationHeadId == null) {
|
||||
return true;
|
||||
}
|
||||
// 校验订单项是否超出
|
||||
return items.size() == 1;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Schema(description = "用户 App - 商品项")
|
||||
|
@ -70,7 +80,9 @@ public class AppTradeOrderSettlementReqVO {
|
|||
public static class Item {
|
||||
|
||||
@Schema(description = "商品 SKU 编号", example = "2048")
|
||||
@NotNull(message = "商品 SKU 编号不能为空")
|
||||
private Long skuId;
|
||||
|
||||
@Schema(description = "购买数量", example = "1")
|
||||
@Min(value = 1, message = "购买数量最小值为 {value}")
|
||||
private Integer count;
|
||||
|
|
|
@ -93,6 +93,7 @@ public interface TradeOrderConvert {
|
|||
new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(item.getCount()));
|
||||
return new ProductSkuUpdateStockReqDTO(items);
|
||||
}
|
||||
|
||||
default ProductSkuUpdateStockReqDTO convertNegative(List<AppTradeOrderSettlementReqVO.Item> list) {
|
||||
List<ProductSkuUpdateStockReqDTO.Item> items = CollectionUtils.convertList(list, item ->
|
||||
new ProductSkuUpdateStockReqDTO.Item().setId(item.getSkuId()).setIncrCount(-item.getCount()));
|
||||
|
@ -209,6 +210,8 @@ public interface TradeOrderConvert {
|
|||
})
|
||||
ProductCommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO);
|
||||
|
||||
TradePriceCalculateReqBO convert(AppTradeOrderSettlementReqVO settlementReqVO);
|
||||
|
||||
default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
|
||||
List<CartDO> cartList) {
|
||||
TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO().setUserId(userId)
|
||||
|
@ -249,17 +252,6 @@ public interface TradeOrderConvert {
|
|||
|
||||
AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "activityId", source = "afterOrderCreateReqBO.combinationActivityId"),
|
||||
@Mapping(target = "spuId", source = "afterOrderCreateReqBO.spuId"),
|
||||
@Mapping(target = "skuId", source = "afterOrderCreateReqBO.skuId"),
|
||||
@Mapping(target = "orderId", source = "afterOrderCreateReqBO.orderId"),
|
||||
@Mapping(target = "userId", source = "afterOrderCreateReqBO.userId"),
|
||||
@Mapping(target = "headId", source = "afterOrderCreateReqBO.combinationHeadId"),
|
||||
@Mapping(target = "combinationPrice", source = "afterOrderCreateReqBO.payPrice"),
|
||||
})
|
||||
CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO afterOrderCreateReqBO);
|
||||
|
||||
List<AppOrderExpressTrackRespDTO> convertList02(List<ExpressTrackRespDTO> list);
|
||||
|
||||
TradeOrderDO convert(TradeOrderUpdateAddressReqVO reqVO);
|
||||
|
@ -280,18 +272,36 @@ public interface TradeOrderConvert {
|
|||
return bo;
|
||||
}
|
||||
|
||||
TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
|
||||
@Mappings({
|
||||
@Mapping(target = "userId", source = "userId"),
|
||||
@Mapping(target = "orderType", source = "calculateRespBO.type"),
|
||||
@Mapping(target = "items", source = "createReqVO.items"),
|
||||
})
|
||||
TradeBeforeOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO, TradePriceCalculateRespBO calculateRespBO);
|
||||
|
||||
|
||||
List<TradeAfterOrderCreateReqBO.Item> convertList(List<TradeOrderItemDO> orderItems);
|
||||
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "combinationActivityId", source = "createReqVO.combinationActivityId"),
|
||||
@Mapping(target = "combinationHeadId", source = "createReqVO.combinationHeadId"),
|
||||
@Mapping(target = "spuId", source = "orderItem.spuId"),
|
||||
@Mapping(target = "skuId", source = "orderItem.skuId"),
|
||||
@Mapping(target = "orderId", source = "tradeOrderDO.id"),
|
||||
@Mapping(target = "userId", source = "userId"),
|
||||
@Mapping(target = "orderId", source = "tradeOrderDO.id"),
|
||||
@Mapping(target = "payPrice", source = "tradeOrderDO.payPrice"),
|
||||
@Mapping(target = "items", source = "orderItems"),
|
||||
})
|
||||
TradeAfterOrderCreateReqBO convert(Long userId, AppTradeOrderCreateReqVO createReqVO,
|
||||
TradeOrderDO tradeOrderDO, TradeOrderItemDO orderItem);
|
||||
TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "activityId", source = "combinationActivityId"),
|
||||
@Mapping(target = "spuId", expression = "java(reqBO.getItems().get(0).getSpuId())"),
|
||||
@Mapping(target = "skuId", expression = "java(reqBO.getItems().get(0).getSkuId())"),// TODO 艿艿看看这里
|
||||
@Mapping(target = "count", expression = "java(reqBO.getItems().get(0).getCount())"),
|
||||
@Mapping(target = "orderId", source = "orderId"),
|
||||
@Mapping(target = "userId", source = "userId"),
|
||||
@Mapping(target = "headId", source = "combinationHeadId"),
|
||||
@Mapping(target = "combinationPrice", source = "payPrice")
|
||||
})
|
||||
CombinationRecordCreateReqDTO convert(TradeAfterOrderCreateReqBO reqBO);
|
||||
|
||||
}
|
||||
|
|
|
@ -26,12 +26,6 @@ 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)
|
||||
.in(TradeOrderItemDO::getSkuId, skuIds));
|
||||
}
|
||||
|
||||
default TradeOrderItemDO selectByIdAndUserId(Long orderItemId, Long loginUserId) {
|
||||
return selectOne(new LambdaQueryWrapperX<TradeOrderItemDO>()
|
||||
.eq(TradeOrderItemDO::getId, orderItemId)
|
||||
|
|
|
@ -119,13 +119,5 @@ public interface TradeOrderQueryService {
|
|||
*/
|
||||
List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
|
||||
|
||||
/**
|
||||
* 获取订单项商品购买数量总和
|
||||
*
|
||||
* @param orderIds 订单编号
|
||||
* @param skuIds sku 编号
|
||||
* @return 订单项商品购买数量总和
|
||||
*/
|
||||
Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
|
|||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
|
||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO;
|
||||
|
@ -169,10 +168,4 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
|
|||
return tradeOrderItemMapper.selectListByOrderId(orderIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getOrderItemCountSumByOrderIdAndSkuId(Collection<Long> orderIds, Collection<Long> skuIds) {
|
||||
List<TradeOrderItemDO> tradeOrderItems = tradeOrderItemMapper.selectListByOrderIdAnSkuId(orderIds, skuIds);
|
||||
return CollectionUtils.getSumValue(tradeOrderItems, TradeOrderItemDO::getCount, Integer::sum);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ import cn.iocoder.yudao.module.trade.service.cart.CartService;
|
|||
import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
|
||||
import cn.iocoder.yudao.module.trade.service.message.TradeMessageService;
|
||||
import cn.iocoder.yudao.module.trade.service.message.bo.TradeOrderMessageWhenDeliveryOrderReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
|
||||
import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
|
@ -253,12 +253,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||
private void beforeCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
|
||||
TradePriceCalculateRespBO calculateRespBO) {
|
||||
// 1. 执行订单创建前置处理器
|
||||
TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
|
||||
beforeOrderCreateReqBO.setOrderType(calculateRespBO.getType());
|
||||
beforeOrderCreateReqBO.setUserId(userId);
|
||||
beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
|
||||
// TODO @puhui999:这里有个纠结点;handler 的定义是只处理指定类型的订单的拓展逻辑;还是通用的 handler,类似可以处理优惠劵等等
|
||||
tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
|
||||
tradeOrderHandlers.forEach(handler ->
|
||||
handler.beforeOrderCreate(TradeOrderConvert.INSTANCE.convert(userId, createReqVO, calculateRespBO)));
|
||||
|
||||
// 2. 下单时扣减商品库存
|
||||
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(createReqVO.getItems()));
|
||||
|
@ -278,9 +275,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||
TradeOrderDO order, List<TradeOrderItemDO> orderItems,
|
||||
TradePriceCalculateRespBO calculateRespBO) {
|
||||
// 1. 执行订单创建后置处理器
|
||||
// TODO @puhui999:从通用性来说,应该不用 orderItems.get(0)
|
||||
tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(
|
||||
TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems.get(0))));
|
||||
TradeOrderConvert.INSTANCE.convert(userId, createReqVO, order, orderItems)));
|
||||
|
||||
// 2. 有使用优惠券时更新
|
||||
// 不在前置扣减的原因,是因为优惠劵要记录使用的订单号
|
||||
|
@ -337,13 +333,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||
throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
|
||||
}
|
||||
|
||||
// 3. 校验活动
|
||||
// 1、拼团活动
|
||||
// TODO @puhui999:这块也抽象到 handler 里
|
||||
if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
|
||||
// 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
|
||||
combinationRecordApi.updateRecordStatusToInProgress(order.getUserId(), order.getId(), LocalDateTime.now());
|
||||
}
|
||||
// 3、订单支付成功后
|
||||
tradeOrderHandlers.forEach(tradeOrderHandler -> tradeOrderHandler.afterPayOrder(new TradeAfterPayOrderReqBO()
|
||||
.setOrderId(order.getId()).setOrderType(order.getType()).setUserId(order.getUserId()).setPayTime(LocalDateTime.now())));
|
||||
|
||||
// 4.1 增加用户积分(赠送)
|
||||
addUserPoint(order.getUserId(), order.getGivePoint(), MemberPointBizTypeEnum.ORDER_GIVE, order.getId());
|
||||
|
@ -470,14 +462,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||
throw exception(ORDER_DELIVERY_FAIL_COMBINATION_RECORD_STATUS_NOT_SUCCESS);
|
||||
}
|
||||
}
|
||||
// 订单类类型:砍价
|
||||
if (Objects.equals(TradeOrderTypeEnum.BARGAIN.getType(), order.getType())) {
|
||||
// 校验订单砍价是否成功
|
||||
// TODO @puhui999:砍价的话,应该不用校验。因为是砍价成功后,才可以下单
|
||||
if (!bargainRecordApi.isBargainRecordSuccess(order.getUserId(), order.getId())) {
|
||||
throw exception(ORDER_DELIVERY_FAIL_BARGAIN_RECORD_STATUS_NOT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
|
@ -644,7 +629,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
|||
}
|
||||
|
||||
// 2. TODO 活动相关库存回滚需要活动 id,活动 id 怎么获取?app 端能否传过来;回复:从订单里拿呀
|
||||
tradeOrderHandlers.forEach(handler -> handler.rollback());
|
||||
tradeOrderHandlers.forEach(handler -> handler.cancelOrder());
|
||||
|
||||
// 3. 回滚库存
|
||||
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package cn.iocoder.yudao.module.trade.service.order.bo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
// TODO 芋艿:在想想这些参数的定义
|
||||
/**
|
||||
|
@ -16,25 +17,71 @@ public class TradeAfterOrderCreateReqBO {
|
|||
|
||||
// ========== 拼团活动相关字段 ==========
|
||||
|
||||
@Schema(description = "拼团活动编号", example = "1024")
|
||||
/**
|
||||
* 拼团活动编号
|
||||
*/
|
||||
private Long combinationActivityId;
|
||||
|
||||
@Schema(description = "拼团团长编号", example = "2048")
|
||||
/**
|
||||
* 拼团团长编号
|
||||
*/
|
||||
private Long combinationHeadId;
|
||||
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
@NotNull(message = "订单编号不能为空")
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@NotNull(message = "用户编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 支付金额
|
||||
*/
|
||||
@NotNull(message = "支付金额不能为空")
|
||||
private Integer payPrice;
|
||||
|
||||
// ========== 购买商品相关字段 ==========
|
||||
|
||||
/**
|
||||
* 订单购买的商品信息
|
||||
*/
|
||||
private List<Item> items;
|
||||
|
||||
/**
|
||||
* 订单商品信息
|
||||
* 记录购买商品的简要核心信息
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
@Valid
|
||||
public static class Item {
|
||||
|
||||
/**
|
||||
* SPU 编号
|
||||
*/
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*
|
||||
* 关联 ProductSkuDO 的 id 编号
|
||||
*/
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
|
||||
/**
|
||||
* 购买的商品数量
|
||||
*/
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package cn.iocoder.yudao.module.trade.service.order.bo;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 订单支付后 Request BO
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Data
|
||||
public class TradeAfterPayOrderReqBO {
|
||||
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
@Schema(description = "订单编号", example = "6")
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 订单类型
|
||||
*
|
||||
* 枚举 {@link TradeOrderTypeEnum}
|
||||
*/
|
||||
@Schema(description = "订单类型", example = "3")
|
||||
private Integer orderType;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
@Schema(description = "用户编号", example = "11")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 订单支付时间
|
||||
*/
|
||||
@Schema(description = "订单支付时间", example = "2023-08-15 10:00:00")
|
||||
private LocalDateTime payTime;
|
||||
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
package cn.iocoder.yudao.module.trade.service.order.bo;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
// TODO 芋艿:在想想这些参数的定义
|
||||
|
||||
/**
|
||||
* 订单创建之前 Request BO
|
||||
*
|
||||
|
@ -34,9 +35,8 @@ public class TradeBeforeOrderCreateReqBO {
|
|||
// ========== 秒杀活动相关字段 ==========
|
||||
|
||||
/**
|
||||
*
|
||||
* 秒杀活动编号
|
||||
*/
|
||||
@Schema(description = "秒杀活动编号", example = "1024")
|
||||
private Long seckillActivityId;
|
||||
|
||||
// ========== 拼团活动相关字段 ==========
|
||||
|
@ -44,13 +44,11 @@ public class TradeBeforeOrderCreateReqBO {
|
|||
/**
|
||||
* 拼团活动编号
|
||||
*/
|
||||
@Schema(description = "拼团活动编号", example = "1024")
|
||||
private Long combinationActivityId;
|
||||
|
||||
/**
|
||||
* 拼团团长编号
|
||||
*/
|
||||
@Schema(description = "拼团团长编号", example = "2048")
|
||||
private Long combinationHeadId;
|
||||
|
||||
// ========== 砍价活动相关字段 ==========
|
||||
|
@ -58,31 +56,39 @@ public class TradeBeforeOrderCreateReqBO {
|
|||
/**
|
||||
* 砍价活动编号
|
||||
*/
|
||||
@Schema(description = "砍价活动编号", example = "123")
|
||||
private Long bargainActivityId;
|
||||
|
||||
// ========== 活动购买商品相关字段 ==========
|
||||
// ========== 购买商品相关字段 ==========
|
||||
|
||||
/**
|
||||
* 商品 SPU 编号
|
||||
* 订单购买的商品信息
|
||||
*/
|
||||
private List<Item> items;
|
||||
|
||||
/**
|
||||
* 订单商品信息
|
||||
* 记录购买商品的简要核心信息
|
||||
*
|
||||
* 关联 ProductSkuDO 的 spuId 编号
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@NotNull(message = "SPU 编号不能为空")
|
||||
private Long spuId;
|
||||
@Data
|
||||
@Valid
|
||||
public static class Item {
|
||||
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*
|
||||
* 关联 ProductSkuDO 的 id 编号
|
||||
*/
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
/**
|
||||
* 商品 SKU 编号
|
||||
*
|
||||
* 关联 ProductSkuDO 的 id 编号
|
||||
*/
|
||||
@NotNull(message = "SKU 编号活动商品不能为空")
|
||||
private Long skuId;
|
||||
|
||||
/**
|
||||
* 购买的商品数量
|
||||
*/
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
/**
|
||||
* 购买的商品数量
|
||||
*/
|
||||
@NotNull(message = "购买数量不能为空")
|
||||
private Integer count;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler;
|
|||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -15,7 +14,7 @@ import javax.annotation.Resource;
|
|||
* @author HUIHUI
|
||||
*/
|
||||
@Component
|
||||
public class TradeBargainHandler implements TradeOrderHandler {
|
||||
public class TradeBargainHandler extends TradeOrderDefaultHandler {
|
||||
|
||||
@Resource
|
||||
private BargainActivityApi bargainActivityApi;
|
||||
|
@ -30,18 +29,11 @@ public class TradeBargainHandler implements TradeOrderHandler {
|
|||
if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取商品信息
|
||||
TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
|
||||
// 扣减砍价活动的库存
|
||||
bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), reqBO.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
|
||||
bargainActivityApi.updateBargainActivityStock(reqBO.getBargainActivityId(), item.getCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.CombinationActivityApi;
|
||||
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
|
||||
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -17,28 +17,27 @@ import javax.annotation.Resource;
|
|||
* @author HUIHUI
|
||||
*/
|
||||
@Component
|
||||
public class TradeCombinationHandler implements TradeOrderHandler {
|
||||
public class TradeCombinationHandler extends TradeOrderDefaultHandler {
|
||||
|
||||
@Resource
|
||||
private CombinationActivityApi combinationActivityApi;
|
||||
@Resource
|
||||
private CombinationRecordApi combinationRecordApi;
|
||||
|
||||
@Override
|
||||
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
|
||||
// 如果是拼团订单;
|
||||
// 如果不是拼团订单则结束
|
||||
if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取商品信息
|
||||
TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
|
||||
// 校验是否满足拼团活动相关限制
|
||||
combinationActivityApi.validateCombination(reqBO.getCombinationActivityId(), reqBO.getUserId(), reqBO.getSkuId(), reqBO.getCount());
|
||||
combinationRecordApi.validateCombinationRecord(reqBO.getCombinationActivityId(), reqBO.getUserId(), item.getSkuId(), item.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||
// TODO @puhui999:需要判断下;
|
||||
if (true) {
|
||||
if (reqBO.getCombinationActivityId() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -47,8 +46,14 @@ public class TradeCombinationHandler implements TradeOrderHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
public void afterPayOrder(TradeAfterPayOrderReqBO reqBO) {
|
||||
// 如果不是拼团订单则结束
|
||||
if (ObjectUtil.notEqual(TradeOrderTypeEnum.COMBINATION.getType(), reqBO.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新拼团状态 TODO puhui999:订单支付失败或订单支付过期删除这条拼团记录
|
||||
combinationRecordApi.updateRecordStatusToInProgress(reqBO.getUserId(), reqBO.getOrderId(), reqBO.getPayTime());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||
|
||||
/**
|
||||
* 订单活动特殊逻辑处理器 handler 默认抽象实现类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
public abstract class TradeOrderDefaultHandler implements TradeOrderHandler {
|
||||
|
||||
@Override
|
||||
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPayOrder(TradeAfterPayOrderReqBO reqBO) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelOrder() {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
package cn.iocoder.yudao.module.trade.service.order.handler;
|
||||
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterPayOrderReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||
|
||||
/**
|
||||
* 订单活动特殊逻辑处理器 handler 接口
|
||||
* 提供订单生命周期钩子接口;订单创建前、订单创建后、订单支付后、订单取消
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
|
@ -24,12 +26,16 @@ public interface TradeOrderHandler {
|
|||
*/
|
||||
void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
|
||||
|
||||
// TODO @puhui999:这个搞成订单取消
|
||||
/**
|
||||
* 回滚
|
||||
* 支付订单后
|
||||
*
|
||||
* @param reqBO 请求
|
||||
*/
|
||||
void rollback();
|
||||
void afterPayOrder(TradeAfterPayOrderReqBO reqBO);
|
||||
|
||||
// TODO @puhui999:再搞个订单项取消哈
|
||||
/**
|
||||
* 订单取消
|
||||
*/
|
||||
void cancelOrder();
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler;
|
|||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeAfterOrderCreateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -15,7 +14,7 @@ import javax.annotation.Resource;
|
|||
* @author HUIHUI
|
||||
*/
|
||||
@Component
|
||||
public class TradeSeckillHandler implements TradeOrderHandler {
|
||||
public class TradeSeckillHandler extends TradeOrderDefaultHandler {
|
||||
|
||||
@Resource
|
||||
private SeckillActivityApi seckillActivityApi;
|
||||
|
@ -30,18 +29,11 @@ public class TradeSeckillHandler implements TradeOrderHandler {
|
|||
if (ObjectUtil.notEqual(TradeOrderTypeEnum.SECKILL.getType(), reqBO.getOrderType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取商品信息
|
||||
TradeBeforeOrderCreateReqBO.Item item = reqBO.getItems().get(0);
|
||||
// 扣减秒杀活动的库存
|
||||
seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
|
||||
seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), item.getSkuId(), item.getCount());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -98,9 +98,19 @@ public class TradePriceCalculateRespBO {
|
|||
* VIP 减免金额,单位:分
|
||||
*/
|
||||
private Integer vipPrice;
|
||||
/**
|
||||
* 秒杀、拼团、砍价活动商品的总金额,单位:分
|
||||
*
|
||||
* 基于 {@link OrderItem#getActivityPrice()} ()} * {@link OrderItem#getCount()} 求和
|
||||
*/
|
||||
private Integer activityPrice;
|
||||
/**
|
||||
* 最终购买金额(总),单位:分
|
||||
*
|
||||
* ==========活动情况===========
|
||||
* = {@link #activityPrice}
|
||||
* + {@link #deliveryPrice}
|
||||
* ==========正常情况===========
|
||||
* = {@link #totalPrice}
|
||||
* - {@link #couponPrice}
|
||||
* - {@link #pointPrice}
|
||||
|
@ -176,9 +186,16 @@ public class TradePriceCalculateRespBO {
|
|||
* VIP 减免金额,单位:分
|
||||
*/
|
||||
private Integer vipPrice;
|
||||
/**
|
||||
* 秒杀、拼团、砍价活动商品的金额,单位:分
|
||||
*/
|
||||
private Integer activityPrice;
|
||||
/**
|
||||
* 应付金额(总),单位:分
|
||||
*
|
||||
* ==========活动情况===========
|
||||
* = {@link #activityPrice} * {@link #count}
|
||||
* + {@link #deliveryPrice}
|
||||
* ==========正常情况===========
|
||||
* = {@link #price} * {@link #count}
|
||||
* - {@link #couponPrice}
|
||||
* - {@link #pointPrice}
|
||||
|
|
|
@ -105,6 +105,9 @@ public class TradePriceCalculatorHelper {
|
|||
if (!item.getSelected()) {
|
||||
return;
|
||||
}
|
||||
// TODO puhui: 需要在这里计算活动的价格
|
||||
// ========== 一、活动情况 ==========
|
||||
// ========== 二、正常情况 ==========
|
||||
price.setTotalPrice(price.getTotalPrice() + item.getPrice() * item.getCount());
|
||||
price.setDiscountPrice(price.getDiscountPrice() + item.getDiscountPrice());
|
||||
price.setDeliveryPrice(price.getDeliveryPrice() + item.getDeliveryPrice());
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
/**
|
||||
* 秒杀活动的 {@link TradePriceCalculator} 实现类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Component
|
||||
@Order(TradePriceCalculator.ORDER_DISCOUNT_ACTIVITY)
|
||||
public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator {
|
||||
|
||||
@Resource
|
||||
private SeckillActivityApi activityApi;
|
||||
|
||||
@Override
|
||||
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// 1、判断订单类型和是否具有秒杀活动编号
|
||||
if (param.getSeckillActivityId() == null) {
|
||||
return;
|
||||
}
|
||||
// 2、获取秒杀活动商品信息
|
||||
List<SeckillActivityProductRespDTO> productList = activityApi.getSeckillActivityProductList(param.getSeckillActivityId(), convertSet(param.getItems(),
|
||||
TradePriceCalculateReqBO.Item::getSkuId));
|
||||
Map<Long, SeckillActivityProductRespDTO> productMap = convertMap(productList, SeckillActivityProductRespDTO::getSkuId);
|
||||
result.getItems().forEach(item -> {
|
||||
SeckillActivityProductRespDTO product = productMap.get(item.getSkuId());
|
||||
item.setActivityPrice(product.getSeckillPrice()); // 设置活动金额
|
||||
});
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue