mall+order: 完善部分 TODO 提到的问题

This commit is contained in:
puhui999 2023-09-13 12:04:13 +08:00
parent 9358639c41
commit a10d77cdfe
30 changed files with 145 additions and 289 deletions

View File

@ -59,14 +59,13 @@ public class ProductSkuRespDTO {
* 商品体积单位m^3 平米 * 商品体积单位m^3 平米
*/ */
private Double volume; private Double volume;
// TODO @puhui999firstBrokeragePrice 尴尬我当时打错了secondBrokeragePrice
/** /**
* 一级分销的佣金单位 * 一级分销的佣金单位
*/ */
private Integer firstBrokerageRecord; private Integer firstBrokeragePrice;
/** /**
* 二级分销的佣金单位 * 二级分销的佣金单位
*/ */
private Integer secondBrokerageRecord; private Integer secondBrokeragePrice;
} }

View File

@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
private Double volume; private Double volume;
@Schema(description = "一级分销的佣金,单位:分", example = "199") @Schema(description = "一级分销的佣金,单位:分", example = "199")
private Integer firstBrokerageRecord; private Integer firstBrokeragePrice;
@Schema(description = "二级分销的佣金,单位:分", example = "19") @Schema(description = "二级分销的佣金,单位:分", example = "19")
private Integer secondBrokerageRecord; private Integer secondBrokeragePrice;
@Schema(description = "属性数组") @Schema(description = "属性数组")
private List<Property> properties; private List<Property> properties;

View File

@ -81,11 +81,11 @@ public class ProductSkuDO extends BaseDO {
/** /**
* 一级分销的佣金单位 * 一级分销的佣金单位
*/ */
private Integer firstBrokerageRecord; private Integer firstBrokeragePrice;
/** /**
* 二级分销的佣金单位 * 二级分销的佣金单位
*/ */
private Integer secondBrokerageRecord; private Integer secondBrokeragePrice;
// ========== 营销相关字段 ========= // ========== 营销相关字段 =========

View File

@ -92,8 +92,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
o.setMarketPrice(generaInt()); o.setMarketPrice(generaInt());
o.setStock(generaInt()); o.setStock(generaInt());
o.setWarnStock(10); o.setWarnStock(10);
o.setFirstBrokerageRecord(generaInt()); o.setFirstBrokeragePrice(generaInt());
o.setSecondBrokerageRecord(generaInt()); o.setSecondBrokeragePrice(generaInt());
// 限制分数为两位数 // 限制分数为两位数
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
@ -143,8 +143,8 @@ public class ProductSpuServiceImplTest extends BaseDbUnitTest {
o.setMarketPrice(generaInt()); o.setMarketPrice(generaInt());
o.setStock(generaInt()); o.setStock(generaInt());
o.setWarnStock(10); o.setWarnStock(10);
o.setFirstBrokerageRecord(generaInt()); o.setFirstBrokeragePrice(generaInt());
o.setSecondBrokerageRecord(generaInt()); o.setSecondBrokeragePrice(generaInt());
// 限制分数为两位数 // 限制分数为两位数
o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); o.setWeight(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));
o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP)); o.setVolume(RandomUtil.randomDouble(10,2, RoundingMode.HALF_UP));

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.promotion.api.combination;
/**
* 拼团活动 Api 接口
*
* @author HUIHUI
*/
public interface CombinationActivityApi {
/**
* 校验是否满足拼团条件
*
* @param activityId 活动编号
* @param userId 用户编号
* @param skuId sku 编号
* @param count 数量
*/
void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
}

View File

@ -1,21 +0,0 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
// TODO @puhui999是不是改成 CombinationActivityApi
/**
* 拼团活动 Api 接口
*
* @author HUIHUI
*/
public interface CombinationApi {
/**
* 更新活动库存
*
* @param reqDTO 请求
*/
// TODO @puhui999应该是更新哇还是校验哈
void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO);
}

View File

@ -1,11 +1,9 @@
package cn.iocoder.yudao.module.promotion.api.combination; package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import javax.validation.Valid; import javax.validation.Valid;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
// TODO @芋艿后面也再撸撸这几个接口 // TODO @芋艿后面也再撸撸这几个接口
@ -33,26 +31,7 @@ public interface CombinationRecordApi {
boolean isCombinationRecordSuccess(Long userId, Long orderId); boolean isCombinationRecordSuccess(Long userId, Long orderId);
/** /**
* 获取拼团记录 * 更新拼团状态为 成功
*
* @param userId 用户编号
* @param activityId 活动编号
* @return 拼团记录列表
*/
List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
/**
* 验证组合限制数
* 校验是否满足限购要求
*
* @param count 本次购买数量
* @param sumCount 已购买数量合计
* @param activityId 活动编号
*/
void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
/**
* 更新拼团状态为成功
* *
* @param userId 用户编号 * @param userId 用户编号
* @param orderId 订单编号 * @param orderId 订单编号
@ -60,7 +39,7 @@ public interface CombinationRecordApi {
void updateRecordStatusToSuccess(Long userId, Long orderId); void updateRecordStatusToSuccess(Long userId, Long orderId);
/** /**
* 更新拼团状态为失败 * 更新拼团状态为 失败
* *
* @param userId 用户编号 * @param userId 用户编号
* @param orderId 订单编号 * @param orderId 订单编号

View File

@ -1,42 +0,0 @@
package cn.iocoder.yudao.module.promotion.api.combination.dto;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
/**
* 拼团活动更新活动库存 Request DTO
*
* @author HUIHUI
*/
@Data
public class CombinationActivityUpdateStockReqDTO {
// TODO @puhui999是不是一个 activityIdcountskuId 参数就完事啦
@NotNull(message = "活动编号不能为空")
private Long activityId;
@NotNull(message = "购买数量不能为空")
private Integer count;
@NotNull(message = "活动商品不能为空")
private Item item;
@Data
@Valid
public static class Item {
@NotNull(message = "SPU 编号不能为空")
private Long spuId;
@NotNull(message = "SKU 编号活动商品不能为空")
private Long skuId;
@NotNull(message = "购买数量不能为空")
private Integer count;
}
}

View File

@ -13,26 +13,39 @@ import javax.validation.constraints.NotNull;
@Data @Data
public class CombinationRecordCreateReqDTO { public class CombinationRecordCreateReqDTO {
// TODO @puhui999注释还是要的哈 /**
* 拼团活动编号
*/
@NotNull(message = "拼团活动编号不能为空") @NotNull(message = "拼团活动编号不能为空")
private Long activityId; private Long activityId;
/**
* spu 编号
*/
@NotNull(message = "spu 编号不能为空") @NotNull(message = "spu 编号不能为空")
private Long spuId; private Long spuId;
/**
* sku 编号
*/
@NotNull(message = "sku 编号不能为空") @NotNull(message = "sku 编号不能为空")
private Long skuId; private Long skuId;
/**
* 订单编号
*/
@NotNull(message = "订单编号不能为空") @NotNull(message = "订单编号不能为空")
private Long orderId; private Long orderId;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空") @NotNull(message = "用户编号不能为空")
private Long userId; private Long userId;
/**
* 团长编号
*/
@NotNull(message = "团长编号不能为空") @NotNull(message = "团长编号不能为空")
private Long headId; private Long headId;
/**
* 拼团商品单价
*/
@NotNull(message = "拼团商品单价不能为空") @NotNull(message = "拼团商品单价不能为空")
private Integer combinationPrice; private Integer combinationPrice;

View File

@ -1,7 +1,5 @@
package cn.iocoder.yudao.module.promotion.api.seckill; package cn.iocoder.yudao.module.promotion.api.seckill;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
/** /**
* 秒杀活动 API 接口 * 秒杀活动 API 接口
* *
@ -12,8 +10,10 @@ public interface SeckillActivityApi {
/** /**
* 更新秒杀库存 * 更新秒杀库存
* *
* @param updateStockReqDTO 请求 * @param activityId 活动编号
* @param skuId sku 编号
* @param count 数量
*/ */
void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO); void updateSeckillStock(Long activityId, Long skuId, Integer count);
} }

View File

@ -1,42 +0,0 @@
package cn.iocoder.yudao.module.promotion.api.seckill.dto;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
/**
* 更新秒杀库存 request DTO
*
* @author HUIHUI
*/
@Data
public class SeckillActivityUpdateStockReqDTO {
// TODO @puhui999可以不用 dto直接 activityIdskuIdcount 即可
@NotNull(message = "活动编号不能为空")
private Long activityId;
@NotNull(message = "购买数量不能为空")
private Integer count;
@NotNull(message = "活动商品不能为空")
private Item item;
@Data
@Valid
public static class Item {
@NotNull(message = "SPU 编号不能为空")
private Long spuId;
@NotNull(message = "SKU 编号活动商品不能为空")
private Long skuId;
@NotNull(message = "购买数量不能为空")
private Integer count;
}
}

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.promotion.api.combination; package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -10,14 +10,15 @@ import javax.annotation.Resource;
* *
* @author HUIHUI * @author HUIHUI
*/ */
public class CombinationApiImpl implements CombinationApi { @Service
public class CombinationActivityApiImpl implements CombinationActivityApi {
@Resource @Resource
private CombinationActivityService activityService; private CombinationActivityService activityService;
@Override @Override
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) { public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
activityService.validateCombination(reqDTO); activityService.validateCombination(activityId, userId, skuId, count);
} }
} }

View File

@ -1,15 +1,12 @@
package cn.iocoder.yudao.module.promotion.api.combination; package cn.iocoder.yudao.module.promotion.api.combination;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum; import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService; import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
/** /**
* 拼团活动 API 实现类 * 拼团活动 API 实现类
@ -32,16 +29,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus()); return CombinationRecordStatusEnum.isSuccess(recordService.getCombinationRecord(userId, orderId).getStatus());
} }
@Override
public List<CombinationRecordRespDTO> getRecordListByUserIdAndActivityId(Long userId, Long activityId) {
return CombinationActivityConvert.INSTANCE.convert(recordService.getRecordListByUserIdAndActivityId(userId, activityId));
}
@Override
public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {
recordService.validateCombinationLimitCount(activityId, count, sumCount);
}
@Override @Override
public void updateRecordStatusToSuccess(Long userId, Long orderId) { public void updateRecordStatusToSuccess(Long userId, Long orderId) {
recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId); recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.SUCCESS.getStatus(), userId, orderId);

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.promotion.api.seckill; package cn.iocoder.yudao.module.promotion.api.seckill;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,8 +17,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
private SeckillActivityService activityService; private SeckillActivityService activityService;
@Override @Override
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
activityService.updateSeckillStock(updateStockReqDTO); activityService.updateSeckillStock(activityId, skuId, count);
} }
} }

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.promotion.convert.combination;
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.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
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.api.combination.dto.CombinationRecordCreateReqDTO; import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO; import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
@ -92,6 +94,19 @@ public interface CombinationActivityConvert {
CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO); CombinationRecordDO convert(CombinationRecordCreateReqDTO reqDTO);
default CombinationRecordDO convert1(CombinationRecordCreateReqDTO reqDTO, CombinationActivityDO activity, MemberUserRespDTO user,
ProductSpuRespDTO spu, ProductSkuRespDTO sku) {
CombinationRecordDO record = convert(reqDTO);
record.setVirtualGroup(false);
record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
record.setUserSize(activity.getUserSize());
record.setNickname(user.getNickname());
record.setAvatar(user.getAvatar());
record.setSpuName(spu.getName());
record.setPicUrl(sku.getPicUrl());
return record;
}
List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean); List<CombinationRecordRespDTO> convert(List<CombinationRecordDO> bean);
} }

View File

@ -39,7 +39,7 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
default int updateActivityStock(Long id, int count) { default int updateActivityStock(Long id, int count) {
return update(null, new LambdaUpdateWrapper<BargainActivityDO>() return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
.eq(BargainActivityDO::getId, id) .eq(BargainActivityDO::getId, id)
.gt(BargainActivityDO::getStock, 0) // TODO @puhui999不是 > 0是要大于 count .gt(BargainActivityDO::getStock, count)
.setSql("stock = stock - " + count)); .setSql("stock = stock - " + count));
} }

View File

@ -34,7 +34,7 @@ public interface SeckillProductMapper extends BaseMapperX<SeckillProductDO> {
default int updateActivityStock(Long id, int count) { default int updateActivityStock(Long id, int count) {
return update(null, new LambdaUpdateWrapper<SeckillProductDO>() return update(null, new LambdaUpdateWrapper<SeckillProductDO>()
.eq(SeckillProductDO::getId, id) .eq(SeckillProductDO::getId, id)
.gt(SeckillProductDO::getStock, 0) // TODO @puhui999不是 > 0是要大于 count .gt(SeckillProductDO::getStock, count)
.setSql("stock = stock - " + count)); .setSql("stock = stock - " + count));
} }

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.promotion.service.combination; package cn.iocoder.yudao.module.promotion.service.combination;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; 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.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@ -74,10 +73,13 @@ public interface CombinationActivityService {
List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds); List<CombinationProductDO> getCombinationProductsByActivityIds(Collection<Long> activityIds);
/** /**
* 更新拼图活动库存 * 校验是否满足拼团条件
* *
* @param reqDTO 请求 * @param activityId 活动编号
* @param userId 用户编号
* @param skuId sku 编号
* @param count 数量
*/ */
void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO); void validateCombination(Long activityId, Long userId, Long skuId, Integer count);
} }

View File

@ -9,7 +9,6 @@ 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.api.combination.dto.CombinationActivityUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityCreateReqVO; 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.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@ -33,7 +32,6 @@ import java.util.Map;
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.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; 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.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*; import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@ -214,24 +212,23 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
} }
@Override @Override
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) { public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
// 1.1 校验拼团活动是否存在 // 1.1 校验拼团活动是否存在
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId()); CombinationActivityDO activity = validateCombinationActivityExists(activityId);
// 1.2 校验活动是否开启 // 1.2 校验活动是否开启
if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE); throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
} }
// 1.3 校验是否超出单次限购数量 // 1.3 校验是否超出单次限购数量
if (activity.getSingleLimitCount() < reqDTO.getCount()) { if (activity.getSingleLimitCount() < count) {
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED); throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
} }
// 2. 校验是否超出总限购数量 // 2. 校验是否超出总限购数量
// TODO @puhui999userId 应该接口传递哈要保证 service 无状态 List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId);
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId( if (CollUtil.isEmpty(recordList)) {
getLoginUserId(), reqDTO.getActivityId()); return;
// TODO @puhui999最好 if true return减少括号层数 }
if (CollUtil.isNotEmpty(recordList)) {
// 过滤出拼团成功的 // 过滤出拼团成功的
// TODO @puhui999count 要不存一个在 record // TODO @puhui999count 要不存一个在 record
List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId, List<Long> skuIds = convertList(recordList, CombinationRecordDO::getSkuId,
@ -242,7 +239,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
if (activity.getTotalLimitCount() < countSum) { if (activity.getTotalLimitCount() < countSum) {
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED); throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
} }
}
} }
} }

View File

@ -57,14 +57,4 @@ public interface CombinationRecordService {
*/ */
List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId); List<CombinationRecordDO> getRecordListByUserIdAndActivityId(Long userId, Long activityId);
/**
* 验证组合限制数
* 校验是否满足限购要求
*
* @param count 本次购买数量
* @param sumCount 已购买数量合计
* @param activityId 活动编号
*/
void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount);
} }

View File

@ -128,19 +128,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
} }
// 2. 创建拼团记录 // 2. 创建拼团记录
// TODO @puhui999可以把 userspusku 一起放 convert 里哈
CombinationRecordDO record = CombinationActivityConvert.INSTANCE.convert(reqDTO);
record.setVirtualGroup(false);
record.setExpireTime(record.getStartTime().plusHours(activity.getLimitDuration()));
record.setUserSize(activity.getUserSize());
MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId()); MemberUserRespDTO user = memberUserApi.getUser(reqDTO.getUserId());
record.setNickname(user.getNickname()); ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
record.setAvatar(user.getAvatar()); ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId()); recordMapper.insert(CombinationActivityConvert.INSTANCE.convert1(reqDTO, activity, user, spu, sku));
record.setSpuName(spu.getName());
ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
record.setPicUrl(sku.getPicUrl());
recordMapper.insert(record);
} }
@Override @Override
@ -153,20 +144,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
return recordMapper.selectListByUserIdAndActivityId(userId, 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,7 +1,6 @@
package cn.iocoder.yudao.module.promotion.service.seckill; package cn.iocoder.yudao.module.promotion.service.seckill;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
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.SeckillActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
@ -37,9 +36,11 @@ public interface SeckillActivityService {
/** /**
* 更新秒杀库存 * 更新秒杀库存
* *
* @param updateStockReqDTO 更新信息 * @param activityId 活动编号
* @param skuId sku 编号
* @param count 数量
*/ */
void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO); void updateSeckillStock(Long activityId, Long skuId, Integer count);
/** /**
* 关闭秒杀活动 * 关闭秒杀活动

View File

@ -7,7 +7,6 @@ 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.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
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.SeckillActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
@ -147,32 +146,32 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) { public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
// 1校验秒杀活动是否存在 // 1校验秒杀活动是否存在
SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId()); SeckillActivityDO seckillActivity = getSeckillActivity(activityId);
// 1.1校验库存是否充足 // 1.1校验库存是否充足
if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) { if (seckillActivity.getTotalStock() < count) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }
// 2获取活动商品 // 2获取活动商品
List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId()); List<SeckillProductDO> products = getSeckillProductListByActivityId(activityId);
// 2.1过滤出购买的商品 // 2.1过滤出购买的商品
SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(updateStockReqDTO.getItem().getSkuId(), item.getSkuId())); SeckillProductDO product = findFirst(products, item -> ObjectUtil.equal(skuId, item.getSkuId()));
// 2.2检查活动商品库存是否充足 // 2.2检查活动商品库存是否充足
boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < updateStockReqDTO.getItem().getCount()) || (product.getStock() - updateStockReqDTO.getItem().getCount()) < 0); boolean isSufficient = product == null || (product.getStock() == 0 || (product.getStock() < count) || (product.getStock() - count) < 0);
if (isSufficient) { if (isSufficient) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }
// 3更新活动商品库存 // 3更新活动商品库存
int updateCount = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount()); int updateCount = seckillProductMapper.updateActivityStock(product.getId(), count);
if (updateCount == 0) { if (updateCount == 0) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }
// 4更新活动库存 // 4更新活动库存
updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount()); updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), count);
if (updateCount == 0) { if (updateCount == 0) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL); throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
} }

View File

@ -14,9 +14,7 @@ import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDT
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
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.sku.dto.ProductSkuUpdateStockReqDTO; import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationActivityUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO; import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO; import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
@ -280,15 +278,9 @@ public interface TradeOrderConvert {
return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId()) return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
.setBasePrice(item.getPayPrice() * item.getCount()) .setBasePrice(item.getPayPrice() * item.getCount())
.setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂标题类似木晴冰雪成功购买云时代的JVM原理与实战茫农成功购买深入拆解消息队列47讲 .setTitle(BrokerageRecordBizTypeEnum.ORDER.getTitle()) // TODO @疯狂标题类似木晴冰雪成功购买云时代的JVM原理与实战茫农成功购买深入拆解消息队列47讲
.setFirstFixedPrice(sku.getFirstBrokerageRecord()).setSecondFixedPrice(sku.getSecondBrokerageRecord()); .setFirstFixedPrice(sku.getFirstBrokeragePrice()).setSecondFixedPrice(sku.getSecondBrokeragePrice());
} }
@Mapping(target = "activityId", source = "reqBO.seckillActivityId")
SeckillActivityUpdateStockReqDTO convert(TradeBeforeOrderCreateReqBO reqBO);
@Mapping(target = "activityId", source = "reqBO.combinationActivityId")
CombinationActivityUpdateStockReqDTO convert1(TradeBeforeOrderCreateReqBO reqBO);
TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO); TradeBeforeOrderCreateReqBO convert(AppTradeOrderCreateReqVO createReqVO);
@Mappings({ @Mappings({

View File

@ -180,9 +180,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
// 1执行订单创建前置处理器 // 1执行订单创建前置处理器
// TODO @puhui999最好也抽个 beforeOrderCreate 方法 // TODO @puhui999最好也抽个 beforeOrderCreate 方法不要 BO 各自处理参数岂不美哉
TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO); TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO)); beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
beforeOrderCreateReqBO.setUserId(userId);
beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum)); beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
// TODO @puhui999这里有个纠结点handler 的定义是只处理指定类型的订单的拓展逻辑还是通用的 handler类似可以处理优惠劵等等 // TODO @puhui999这里有个纠结点handler 的定义是只处理指定类型的订单的拓展逻辑还是通用的 handler类似可以处理优惠劵等等
tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO)); tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
@ -726,7 +727,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
} }
// TODO 活动相关库存回滚需要活动 id活动 id 怎么获取app 端能否传过来 // TODO 活动相关库存回滚需要活动 id活动 id 怎么获取app 端能否传过来
tradeOrderHandlers.forEach(handler -> handler.rollbackStock()); tradeOrderHandlers.forEach(handler -> handler.rollback());
// 2.回滚库存 // 2.回滚库存
List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id); List<TradeOrderItemDO> orderItems = tradeOrderItemMapper.selectListByOrderId(id);

View File

@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.service.order.bo;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
// TODO 芋艿在想想这些参数的定义 // TODO 芋艿在想想这些参数的定义
@ -34,25 +33,16 @@ public class TradeBeforeOrderCreateReqBO {
@Schema(description = "砍价活动编号", example = "123") @Schema(description = "砍价活动编号", example = "123")
private Long bargainActivityId; private Long bargainActivityId;
@NotNull(message = "购买数量不能为空")
private Integer count;
@NotNull(message = "活动商品不能为空")
private Item item;
@Data
@Valid
public static class Item {
@NotNull(message = "SPU 编号不能为空") @NotNull(message = "SPU 编号不能为空")
private Long spuId; private Long spuId;
@NotNull(message = "SKU 编号活动商品不能为空") @NotNull(message = "SKU 编号活动商品不能为空")
private Long skuId; private Long skuId;
@NotNull(message = "用户编号不能为空")
private Long userId;
@NotNull(message = "购买数量不能为空") @NotNull(message = "购买数量不能为空")
private Integer count; private Integer count;
}
} }

View File

@ -22,7 +22,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
@Override @Override
public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) { public void beforeOrderCreate(TradeBeforeOrderCreateReqBO reqBO) {
// 如果是秒杀订单 // 如果是砍价订单
if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) { if (ObjectUtil.notEqual(TradeOrderTypeEnum.BARGAIN.getType(), reqBO.getOrderType())) {
return; return;
} }
@ -37,7 +37,7 @@ public class TradeBargainHandler implements TradeOrderHandler {
} }
@Override @Override
public void rollbackStock() { public void rollback() {
} }

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.trade.service.order.handler; package cn.iocoder.yudao.module.trade.service.order.handler;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi; import cn.iocoder.yudao.module.promotion.api.combination.CombinationActivityApi;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi; import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
@ -20,7 +20,7 @@ import javax.annotation.Resource;
public class TradeCombinationHandler implements TradeOrderHandler { public class TradeCombinationHandler implements TradeOrderHandler {
@Resource @Resource
private CombinationApi combinationApi; private CombinationActivityApi combinationActivityApi;
@Resource @Resource
private CombinationRecordApi combinationRecordApi; private CombinationRecordApi combinationRecordApi;
@ -32,7 +32,7 @@ public class TradeCombinationHandler implements TradeOrderHandler {
} }
// 校验是否满足拼团活动相关限制 // 校验是否满足拼团活动相关限制
combinationApi.validateCombination(TradeOrderConvert.INSTANCE.convert1(reqBO)); combinationActivityApi.validateCombination(reqBO.getCombinationActivityId(), reqBO.getUserId(), reqBO.getSkuId(), reqBO.getCount());
} }
@Override @Override
@ -42,7 +42,7 @@ public class TradeCombinationHandler implements TradeOrderHandler {
} }
@Override @Override
public void rollbackStock() { public void rollback() {
} }

View File

@ -25,8 +25,8 @@ public interface TradeOrderHandler {
void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO); void afterOrderCreate(TradeAfterOrderCreateReqBO reqBO);
/** /**
* 回滚活动相关库存 * 回滚
*/ */
void rollbackStock(); void rollback();
} }

View File

@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order.handler;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi; import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; 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.TradeAfterOrderCreateReqBO;
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO; import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
@ -28,7 +27,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
return; return;
} }
seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO)); seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
} }
@Override @Override
@ -37,7 +36,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
} }
@Override @Override
public void rollbackStock() { public void rollback() {
} }