Merge branch 'feature/mall_product' of https://gitee.com/puhui999/ruoyi-vue-pro into feature/mall_product

 Conflicts:
	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
This commit is contained in:
YunaiV 2023-09-20 00:03:18 +08:00
commit 2278ad4652
49 changed files with 530 additions and 467 deletions

View File

@ -43,6 +43,16 @@ public class LocalDateTimeUtils {
return LocalDateTime.of(year, mouth, day, 0, 0, 0);
}
/**
* 创建指定时间
*
* @param timeStr 时间字符串
* @return 指定时间
*/
public static LocalDateTime buildTime(String timeStr) {
return LocalDateTime.of(LocalDate.now(), LocalTime.parse(timeStr));
}
public static LocalDateTime[] buildBetweenTime(int year1, int mouth1, int day1,
int year2, int mouth2, int day2) {
return new LocalDateTime[]{buildTime(year1, mouth1, day1), buildTime(year2, mouth2, day2)};
@ -62,6 +72,22 @@ public class LocalDateTimeUtils {
return LocalDateTimeUtil.isIn(LocalDateTime.now(), startTime, endTime);
}
/**
* 判断当前时间是否在该时间范围内
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return 是否
*/
public static boolean isBetween(String startTime, String endTime) {
if (startTime == null || endTime == null) {
return false;
}
LocalDate nowDate = LocalDate.now();
return LocalDateTimeUtil.isIn(LocalDateTime.now(), LocalDateTime.of(nowDate, LocalTime.parse(startTime)),
LocalDateTime.of(nowDate, LocalTime.parse(endTime)));
}
/**
* 判断时间段是否重叠
*

View File

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

View File

@ -1,6 +1,5 @@
package cn.iocoder.yudao.module.product.api.spu.dto;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import lombok.Data;
@ -31,6 +30,12 @@ public class ProductSpuRespDTO {
* 关键字
*/
private String keyword;
/**
* 单位
*
* 对应 product_unit 数据字典
*/
private Integer unit;
/**
* 商品简介
*/

View File

@ -51,10 +51,10 @@ public class ProductSkuBaseVO {
private Double volume;
@Schema(description = "一级分销的佣金,单位:分", example = "199")
private Integer firstBrokerageRecord;
private Integer firstBrokeragePrice;
@Schema(description = "二级分销的佣金,单位:分", example = "19")
private Integer secondBrokerageRecord;
private Integer secondBrokeragePrice;
@Schema(description = "属性数组")
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.setStock(generaInt());
o.setWarnStock(10);
o.setFirstBrokerageRecord(generaInt());
o.setSecondBrokerageRecord(generaInt());
o.setFirstBrokeragePrice(generaInt());
o.setSecondBrokeragePrice(generaInt());
// 限制分数为两位数
o.setWeight(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.setStock(generaInt());
o.setWarnStock(10);
o.setFirstBrokerageRecord(generaInt());
o.setSecondBrokerageRecord(generaInt());
o.setFirstBrokeragePrice(generaInt());
o.setSecondBrokeragePrice(generaInt());
// 限制分数为两位数
o.setWeight(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;
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 java.time.LocalDateTime;
import java.util.List;
// TODO @芋艿后面也再撸撸这几个接口
@ -33,26 +31,7 @@ public interface CombinationRecordApi {
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 orderId 订单编号
@ -60,7 +39,7 @@ public interface CombinationRecordApi {
void updateRecordStatusToSuccess(Long userId, Long orderId);
/**
* 更新拼团状态为失败
* 更新拼团状态为 失败
*
* @param userId 用户编号
* @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
public class CombinationRecordCreateReqDTO {
// TODO @puhui999注释还是要的哈
/**
* 拼团活动编号
*/
@NotNull(message = "拼团活动编号不能为空")
private Long activityId;
/**
* spu 编号
*/
@NotNull(message = "spu 编号不能为空")
private Long spuId;
/**
* sku 编号
*/
@NotNull(message = "sku 编号不能为空")
private Long skuId;
/**
* 订单编号
*/
@NotNull(message = "订单编号不能为空")
private Long orderId;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 团长编号
*/
@NotNull(message = "团长编号不能为空")
private Long headId;
/**
* 拼团商品单价
*/
@NotNull(message = "拼团商品单价不能为空")
private Integer combinationPrice;

View File

@ -1,7 +1,5 @@
package cn.iocoder.yudao.module.promotion.api.seckill;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
/**
* 秒杀活动 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

@ -56,6 +56,7 @@ public interface ErrorCodeConstants {
ErrorCode SECKILL_ACTIVITY_DELETE_FAIL_STATUS_NOT_CLOSED_OR_END = new ErrorCode(1013008004, "秒杀活动未关闭或未结束,不能删除");
ErrorCode SECKILL_ACTIVITY_CLOSE_FAIL_STATUS_CLOSED = new ErrorCode(1013008005, "秒杀活动已关闭,不能重复关闭");
ErrorCode SECKILL_ACTIVITY_UPDATE_STOCK_FAIL = new ErrorCode(1013008006, "秒杀失败,原因秒杀库存不足");
ErrorCode SECKILL_ACTIVITY_FAIL_STATUS_CLOSED = new ErrorCode(1013008007, "秒杀活动已关闭");
// ========== 秒杀时段 1013009000 ==========
ErrorCode SECKILL_CONFIG_NOT_EXISTS = new ErrorCode(1013009000, "秒杀时段不存在");

View File

@ -77,6 +77,10 @@
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,9 +1,7 @@
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 org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@ -13,15 +11,14 @@ import javax.annotation.Resource;
* @author HUIHUI
*/
@Service
@Validated
public class CombinationApiImpl implements CombinationApi {
public class CombinationActivityApiImpl implements CombinationActivityApi {
@Resource
private CombinationActivityService activityService;
@Override
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
activityService.validateCombination(reqDTO);
public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
activityService.validateCombination(activityId, userId, skuId, count);
}
}

View File

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

View File

@ -1,6 +1,5 @@
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 org.springframework.stereotype.Service;
@ -18,8 +17,8 @@ public class SeckillActivityApiImpl implements SeckillActivityApi {
private SeckillActivityService activityService;
@Override
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
activityService.updateSeckillStock(updateStockReqDTO);
public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
activityService.updateSeckillStock(activityId, skuId, count);
}
}

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.promotion.controller.admin.bargain;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
@ -19,6 +22,7 @@ import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -30,6 +34,8 @@ public class BargainActivityController {
@Resource
private BargainActivityService activityService;
@Resource
private ProductSpuApi spuApi;
@PostMapping("/create")
@Operation(summary = "创建砍价活动")
@ -73,7 +79,8 @@ public class BargainActivityController {
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
return success(BargainActivityConvert.INSTANCE.convertPage(activityService.getBargainActivityPage(pageVO)));
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(pageResult.getList(), BargainActivityDO::getSpuId));
return success(BargainActivityConvert.INSTANCE.convertPage(pageResult, spuList));
}
}

View File

@ -1,12 +1,19 @@
package cn.iocoder.yudao.module.promotion.controller.app.bargain;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.convert.bargain.BargainActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
@ -14,8 +21,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.util.ArrayList;
import javax.annotation.Resource;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -25,86 +31,49 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@RequestMapping("/promotion/bargain-activity")
@Validated
public class AppBargainActivityController {
@Resource
private BargainActivityService bargainActivityService;
@Resource
private ProductSpuApi spuApi;
@GetMapping("/page")
@Operation(summary = "获得砍价活动活动") // TODO 芋艿只查询进行中且在时间范围内的
// TODO 芋艿缺少 swagger 注解
@Operation(summary = "获得砍价活动分页")
public CommonResult<PageResult<AppBargainActivityRespVO>> getBargainActivityPage(PageParam pageReqVO) {
List<AppBargainActivityRespVO> activityList = new ArrayList<>();
AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO();
activity1.setId(1L);
activity1.setName("618 大砍价");
activity1.setSpuId(2048L);
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
activity1.setMarketPrice(50);
activity1.setBargainPrice(100);
activity1.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));
activity1.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));
activity1.setStock(10);
activityList.add(activity1);
PageResult<BargainActivityDO> result = bargainActivityService.getBargainActivityAppPage(pageReqVO);
if (CollUtil.isEmpty(result.getList())) {
return success(PageResult.empty(result.getTotal()));
}
AppBargainActivityRespVO activity2 = new AppBargainActivityRespVO();
activity2.setId(2L);
activity2.setName("双十一砍价");
activity2.setSpuId(4096L);
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
activity2.setMarketPrice(100);
activity2.setBargainPrice(200);
activity2.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));
activity2.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(1)));
activity2.setStock(0);
activityList.add(activity2);
return success(new PageResult<>(activityList, 10L));
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(result.getList(), BargainActivityDO::getSpuId));
return success(BargainActivityConvert.INSTANCE.convertAppPage(result, spuList));
}
@GetMapping("/list")
@Operation(summary = "获得砍价活动列表", description = "用于小程序首页")
// TODO 芋艿增加 Spring Cache
// TODO 芋艿缺少 swagger 注解
@Parameter(name = "count", description = "需要展示的数量", example = "6")
public CommonResult<List<AppBargainActivityRespVO>> getBargainActivityList(
@RequestParam(name = "count", defaultValue = "6") Integer count) {
List<AppBargainActivityRespVO> activityList = new ArrayList<>();
AppBargainActivityRespVO activity1 = new AppBargainActivityRespVO();
activity1.setId(1L);
activity1.setName("618 大砍价");
activity1.setSpuId(2048L);
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
activity1.setMarketPrice(50);
activity1.setBargainPrice(100);
activityList.add(activity1);
List<BargainActivityDO> list = bargainActivityService.getBargainActivityAppList(count);
if (CollUtil.isEmpty(list)) {
return success(BargainActivityConvert.INSTANCE.convertAppList(list));
}
AppBargainActivityRespVO activity2 = new AppBargainActivityRespVO();
activity2.setId(2L);
activity2.setName("双十一砍价");
activity2.setSpuId(4096L);
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
activity2.setMarketPrice(100);
activity2.setBargainPrice(200);
activityList.add(activity2);
return success(activityList);
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(list, BargainActivityDO::getSpuId));
// TODO 芋艿增加 Spring Cache
return success(BargainActivityConvert.INSTANCE.convertAppList(list, spuList));
}
@GetMapping("/get-detail")
@Operation(summary = "获得砍价活动详情")
// TODO 芋艿缺少 swagger 注解
@Parameter(name = "id", description = "活动编号", example = "1")
public CommonResult<AppBargainActivityDetailRespVO> getBargainActivityDetail(@RequestParam("id") Long id) {
AppBargainActivityDetailRespVO activity = new AppBargainActivityDetailRespVO();
activity.setId(2L);
activity.setName("618 大砍价");
activity.setSpuId(2048L);
activity.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
activity.setMarketPrice(50);
activity.setBargainPrice(100);
activity.setStock(10);
activity.setUnitName("");
activity.setPrice(40);
activity.setStartTime(LocalDateTimeUtils.addTime(Duration.ofDays(-2)));
activity.setEndTime(LocalDateTimeUtils.addTime(Duration.ofDays(-10)));
activity.setDescription("我吃西红柿");
activity.setSuccessCount(10);
return success(activity);
BargainActivityDO activity = bargainActivityService.getBargainActivity(id);
if (activity == null) {
return success(null);
}
ProductSpuRespDTO spu = spuApi.getSpu(activity.getSpuId());
return success(BargainActivityConvert.INSTANCE.convert1(activity, spu));
}
}

View File

@ -45,7 +45,7 @@ public class AppBargainActivityDetailRespVO {
@Schema(description = "商品单位", required = true, example = "") // SPU unit 读取然后转换
private String unitName;
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
private Integer bargainPrice;
@Schema(description = "砍价成功数量", required = true, example = "100")

View File

@ -36,7 +36,7 @@ public class AppBargainActivityRespVO {
@Schema(description = "商品市场价,单位:分", required = true, example = "50") // SPU marketPrice 读取
private Integer marketPrice;
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100") // 从砍价商品里取最低价
@Schema(description = "砍价最低金额,单位:分", required = true, example = "100")
private Integer bargainPrice;
}

View File

@ -1,136 +1,114 @@
package cn.iocoder.yudao.module.promotion.controller.app.seckill;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.context.annotation.Lazy;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.ArrayList;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.findFirst;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.isBetween;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.SECKILL_ACTIVITY_FAIL_STATUS_CLOSED;
@Tag(name = "用户 App - 秒杀活动")
@RestController
@RequestMapping("/promotion/seckill-activity")
@Validated
public class AppSeckillActivityController {
@Resource
private SeckillActivityService activityService;
@Resource
@Lazy
private SeckillConfigService configService;
@Resource
private ProductSpuApi spuApi;
@GetMapping("/get-now")
@Operation(summary = "获得当前秒杀活动") // 提供给首页使用
// TODO 芋艿需要增加 spring cache
public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();
respVO.setConfig(new AppSeckillConfigRespVO().setId(10L).setStartTime("01:00").setEndTime("09:59"));
List<AppSeckillActivityRespVO> activityList = new ArrayList<>();
AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();
activity1.setId(1L);
activity1.setName("618 大秒杀");
activity1.setSpuId(2048L);
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
activity1.setMarketPrice(50);
activity1.setSeckillPrice(100);
activityList.add(activity1);
// 1获取当前时间处在哪个秒杀阶段
List<SeckillConfigDO> configList = configService.getSeckillConfigList();
SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
// 11 时段不存在直接返回 null
if (filteredConfig == null) {
return success(null);
}
AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();
activity2.setId(2L);
activity2.setName("双十一大秒杀");
activity2.setSpuId(4096L);
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
activity2.setMarketPrice(100);
activity2.setSeckillPrice(200);
activityList.add(activity2);
respVO.setActivities(activityList);
return success(respVO);
// 2查询满足当前阶段的活动
List<SeckillActivityDO> activityList = activityService.getSeckillActivityListByConfigIds(Arrays.asList(filteredConfig.getId()));
List<SeckillActivityDO> filteredList = filterList(activityList, item -> ObjectUtil.equal(item.getStatus(), CommonStatusEnum.ENABLE.getStatus()));
// 21 获取 spu 信息
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(filteredList, SeckillActivityDO::getSpuId));
return success(SeckillActivityConvert.INSTANCE.convert(filteredConfig, filteredList, spuList));
}
@GetMapping("/page")
@Operation(summary = "获得秒杀活动分页")
// TODO @芋艿分页参数
public CommonResult<PageResult<AppSeckillActivityRespVO>> getSeckillActivityPage(AppSeckillActivityPageReqVO pageReqVO) {
List<AppSeckillActivityRespVO> activityList = new ArrayList<>();
AppSeckillActivityRespVO activity1 = new AppSeckillActivityRespVO();
activity1.setId(1L);
activity1.setName("618 大秒杀");
activity1.setSpuId(2048L);
activity1.setPicUrl("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg");
activity1.setMarketPrice(50);
activity1.setSeckillPrice(100);
activity1.setUnitName("");
activity1.setStock(1);
activity1.setTotalStock(2);
activityList.add(activity1);
AppSeckillActivityRespVO activity2 = new AppSeckillActivityRespVO();
activity2.setId(2L);
activity2.setName("双十一大秒杀");
activity2.setSpuId(4096L);
activity2.setPicUrl("https://static.iocoder.cn/mall/132.jpeg");
activity2.setMarketPrice(100);
activity2.setSeckillPrice(200);
activity2.setUnitName("");
activity2.setStock(2);
activity2.setTotalStock(3);
activityList.add(activity2);
return success(new PageResult<>(activityList, 100L));
// 1查询满足当前阶段的活动
PageResult<SeckillActivityDO> pageResult = activityService.getSeckillActivityAppPageByConfigId(pageReqVO);
// 11 获取 spu 信息
List<ProductSpuRespDTO> spuList = spuApi.getSpuList(CollectionUtils.convertList(pageResult.getList(), SeckillActivityDO::getSpuId));
return success(SeckillActivityConvert.INSTANCE.convertPage(pageResult, spuList));
}
@GetMapping("/get-detail")
@Operation(summary = "获得秒杀活动明细")
@Parameter(name = "id", description = "活动编号", required = true, example = "1024")
public CommonResult<AppSeckillActivityDetailRespVO> getSeckillActivity(@RequestParam("id") Long id) {
// TODO 芋艿如果禁用的时候需要抛出异常
AppSeckillActivityDetailRespVO obj = new AppSeckillActivityDetailRespVO();
// 设置其属性的值
obj.setId(id);
obj.setName("晚九点限时秒杀");
obj.setStatus(1);
obj.setStartTime(LocalDateTime.of(2023, 6, 16, 0, 0, 0));
obj.setEndTime(LocalDateTime.of(2023, 6, 20, 23, 59, 0));
obj.setSpuId(633L);
obj.setSingleLimitCount(2);
obj.setTotalLimitCount(3);
obj.setStock(100);
obj.setTotalStock(200);
// 1获取当前时间处在哪个秒杀阶段
List<SeckillConfigDO> configList = configService.getSeckillConfigList();
SeckillConfigDO filteredConfig = findFirst(configList, config -> ObjectUtil.equal(config.getStatus(),
CommonStatusEnum.ENABLE.getStatus()) && isBetween(config.getStartTime(), config.getEndTime()));
// 11 时段不存在直接返回 null
if (filteredConfig == null) {
return success(null);
}
// 创建一个Product对象的列表
List<AppSeckillActivityDetailRespVO.Product> productList = new ArrayList<>();
// 创建三个新的Product对象并设置其属性的值
AppSeckillActivityDetailRespVO.Product product1 = new AppSeckillActivityDetailRespVO.Product();
product1.setSkuId(1L);
product1.setSeckillPrice(100);
product1.setStock(50);
// 将第一个Product对象添加到列表中
productList.add(product1);
// 创建第二个Product对象并设置其属性的值
AppSeckillActivityDetailRespVO.Product product2 = new AppSeckillActivityDetailRespVO.Product();
product2.setSkuId(2L);
product2.setSeckillPrice(200);
product2.setStock(100);
// 将第二个Product对象添加到列表中
productList.add(product2);
// 创建第三个Product对象并设置其属性的值
AppSeckillActivityDetailRespVO.Product product3 = new AppSeckillActivityDetailRespVO.Product();
product3.setSkuId(3L);
product3.setSeckillPrice(300);
product3.setStock(150);
// 将第三个Product对象添加到列表中
productList.add(product3);
// 将Product列表设置为对象的属性值
obj.setProducts(productList);
return success(obj);
// 2获取活动
SeckillActivityDO seckillActivity = activityService.getSeckillActivity(id);
if (seckillActivity == null) {
return success(null);
}
// TODO 芋艿如果禁用的时候需要抛出异常
if (ObjectUtil.equal(seckillActivity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
throw exception(SECKILL_ACTIVITY_FAIL_STATUS_CLOSED);
}
// 3获取活动商品
List<SeckillProductDO> products = activityService.getSeckillProductListByActivityId(seckillActivity.getId());
return success(SeckillActivityConvert.INSTANCE.convert3(seckillActivity, products, filteredConfig));
}
}

View File

@ -1,7 +1,12 @@
package cn.iocoder.yudao.module.promotion.controller.app.seckill;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
@ -9,7 +14,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -19,18 +25,26 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@RequestMapping("/promotion/seckill-config")
@Validated
public class AppSeckillConfigController {
@Resource
private SeckillConfigService configService;
@GetMapping("/list")
@Operation(summary = "获得秒杀时间段列表")
public CommonResult<List<AppSeckillConfigRespVO>> getSeckillConfigList() {
return success(Arrays.asList(
new AppSeckillConfigRespVO().setId(1L).setStartTime("00:00").setEndTime("09:59")
.setSliderPicUrls(Arrays.asList("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg",
"https://static.iocoder.cn/mall/132.jpeg")),
new AppSeckillConfigRespVO().setId(2L).setStartTime("10:00").setEndTime("12:59"),
new AppSeckillConfigRespVO().setId(2L).setStartTime("13:00").setEndTime("22:59"),
new AppSeckillConfigRespVO().setId(2L).setStartTime("23:00").setEndTime("23:59")
));
List<SeckillConfigDO> list = configService.getSeckillConfigListByStatus(CommonStatusEnum.ENABLE.getStatus());
if (CollectionUtil.isEmpty(list)) {
return success(Collections.emptyList());
}
return success(SeckillConfigConvert.INSTANCE.convertList2(list));
//return success(Arrays.asList(
// new AppSeckillConfigRespVO().setId(1L).setStartTime("00:00").setEndTime("09:59")
// .setSliderPicUrls(Arrays.asList("https://static.iocoder.cn/mall/a79f5d2ea6bf0c3c11b2127332dfe2df.jpg",
// "https://static.iocoder.cn/mall/132.jpeg")),
// new AppSeckillConfigRespVO().setId(2L).setStartTime("10:00").setEndTime("12:59"),
// new AppSeckillConfigRespVO().setId(2L).setStartTime("13:00").setEndTime("22:59"),
// new AppSeckillConfigRespVO().setId(2L).setStartTime("23:00").setEndTime("23:59")
//));
}
}

View File

@ -19,7 +19,7 @@ public class AppSeckillActivityDetailRespVO {
@Schema(description = "活动状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
// TODO @芋艿开始时间结束时间要和场次结合起来就是要算到当前场次是几点哈
// TODO @芋艿开始时间结束时间要和场次结合起来就是要算到当前场次是几点哈;
@Schema(description = "活动开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime startTime;

View File

@ -31,7 +31,6 @@ public class AppSeckillActivityRespVO {
private Integer totalStock;
@Schema(description = "秒杀金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
// 从秒杀商品里取最低价
private Integer seckillPrice;
}

View File

@ -1,14 +1,24 @@
package cn.iocoder.yudao.module.promotion.convert.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.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.controller.admin.bargain.vo.BargainActivityBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.bargain.vo.activity.AppBargainActivityRespVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
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.MapUtils.findAndThen;
/**
* 拼团活动 Convert
@ -30,4 +40,60 @@ public interface BargainActivityConvert {
PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page);
default PageResult<BargainActivityRespVO> convertPage(PageResult<BargainActivityDO> page, List<ProductSpuRespDTO> spuList) {
PageResult<BargainActivityRespVO> result = convertPage(page);
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
List<BargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
item.setPicUrl(spu.getPicUrl());
item.setSpuName(spu.getName());
});
return item;
});
result.setList(list);
return result;
}
AppBargainActivityDetailRespVO convert1(BargainActivityDO bean);
default AppBargainActivityDetailRespVO convert1(BargainActivityDO bean, ProductSpuRespDTO spu) {
AppBargainActivityDetailRespVO detail = convert1(bean);
if (spu != null) {
detail.setPicUrl(spu.getPicUrl());
detail.setMarketPrice(spu.getMarketPrice());
detail.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
}
return detail;
}
PageResult<AppBargainActivityRespVO> convertAppPage(PageResult<BargainActivityDO> page);
default PageResult<AppBargainActivityRespVO> convertAppPage(PageResult<BargainActivityDO> page, List<ProductSpuRespDTO> spuList) {
PageResult<AppBargainActivityRespVO> result = convertAppPage(page);
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
List<AppBargainActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
});
return item;
});
result.setList(list);
return result;
}
List<AppBargainActivityRespVO> convertAppList(List<BargainActivityDO> list);
default List<AppBargainActivityRespVO> convertAppList(List<BargainActivityDO> list, List<ProductSpuRespDTO> spuList) {
List<AppBargainActivityRespVO> activityList = convertAppList(list);
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
return CollectionUtils.convertList(activityList, item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
});
return item;
});
}
}

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.util.collection.CollectionUtils;
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.promotion.api.combination.dto.CombinationRecordCreateReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
@ -92,6 +94,19 @@ public interface CombinationActivityConvert {
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);
}

View File

@ -3,15 +3,22 @@ package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity;
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.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.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;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
@ -20,6 +27,10 @@ import org.mapstruct.factory.Mappers;
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.MapUtils.findAndThen;
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
/**
* 秒杀活动 Convert
*
@ -79,4 +90,50 @@ public interface SeckillActivityConvert {
List<SeckillProductRespVO> convertList2(List<SeckillProductDO> list);
List<AppSeckillActivityRespVO> convertList3(List<SeckillActivityDO> activityList);
default AppSeckillActivityNowRespVO convert(SeckillConfigDO filteredConfig, List<SeckillActivityDO> activityList, List<ProductSpuRespDTO> spuList) {
AppSeckillActivityNowRespVO respVO = new AppSeckillActivityNowRespVO();
respVO.setConfig(SeckillConfigConvert.INSTANCE.convert1(filteredConfig));
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
respVO.setActivities(CollectionUtils.convertList(convertList3(activityList), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
});
return item;
}));
return respVO;
}
PageResult<AppSeckillActivityRespVO> convertPage1(PageResult<SeckillActivityDO> pageResult);
default PageResult<AppSeckillActivityRespVO> convertPage(PageResult<SeckillActivityDO> pageResult, List<ProductSpuRespDTO> spuList) {
PageResult<AppSeckillActivityRespVO> result = convertPage1(pageResult);
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
List<AppSeckillActivityRespVO> list = CollectionUtils.convertList(result.getList(), item -> {
findAndThen(spuMap, item.getSpuId(), spu -> {
item.setPicUrl(spu.getPicUrl());
item.setMarketPrice(spu.getMarketPrice());
item.setUnitName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.PRODUCT_UNIT, spu.getUnit()));
});
return item;
});
result.setList(list);
return result;
}
AppSeckillActivityDetailRespVO convert2(SeckillActivityDO seckillActivity);
List<AppSeckillActivityDetailRespVO.Product> convertList1(List<SeckillProductDO> products);
default AppSeckillActivityDetailRespVO convert3(SeckillActivityDO seckillActivity, List<SeckillProductDO> products, SeckillConfigDO filteredConfig) {
AppSeckillActivityDetailRespVO respVO = convert2(seckillActivity);
respVO.setProducts(convertList1(products));
respVO.setStartTime(buildTime(filteredConfig.getStartTime()));
respVO.setEndTime(buildTime(filteredConfig.getEndTime()));
return respVO;
}
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.Seck
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigSimpleRespVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillconfig.SeckillConfigDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@ -33,4 +34,7 @@ public interface SeckillConfigConvert {
PageResult<SeckillConfigRespVO> convertPage(PageResult<SeckillConfigDO> page);
List<AppSeckillConfigRespVO> convertList2(List<SeckillConfigDO> list);
AppSeckillConfigRespVO convert1(SeckillConfigDO filteredConfig);
}

View File

@ -87,7 +87,7 @@ public class SeckillActivityDO extends BaseDO {
*/
private Integer singleLimitCount;
/**
* 秒杀库存
* 秒杀库存(剩余库存秒杀时扣减)
*/
private Integer stock;
/**

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
@ -8,6 +9,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityD
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.time.LocalDateTime;
import java.util.List;
/**
@ -39,8 +41,15 @@ public interface BargainActivityMapper extends BaseMapperX<BargainActivityDO> {
default int updateActivityStock(Long id, int count) {
return update(null, new LambdaUpdateWrapper<BargainActivityDO>()
.eq(BargainActivityDO::getId, id)
.gt(BargainActivityDO::getStock, 0) // TODO @puhui999不是 > 0是要大于 count
.gt(BargainActivityDO::getStock, count)
.setSql("stock = stock - " + count));
}
default PageResult<BargainActivityDO> selectAppPage(PageParam pageReqVO, Integer status, LocalDateTime now) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<BargainActivityDO>()
.eq(BargainActivityDO::getStatus, status)
.le(BargainActivityDO::getStartTime, now)
.ge(BargainActivityDO::getEndTime, now));
}
}

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
@ -24,7 +25,7 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
.likeIfPresent(SeckillActivityDO::getName, reqVO.getName())
.eqIfPresent(SeckillActivityDO::getStatus, reqVO.getStatus())
.betweenIfPresent(SeckillActivityDO::getCreateTime, reqVO.getCreateTime())
.apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ",time_ids) > 0")
.apply(ObjectUtil.isNotNull(reqVO.getConfigId()), "FIND_IN_SET(" + reqVO.getConfigId() + ", config_ids) > 0")
.orderByDesc(SeckillActivityDO::getId));
}
@ -48,4 +49,10 @@ public interface SeckillActivityMapper extends BaseMapperX<SeckillActivityDO> {
.setSql("totalStock = totalStock - " + count));
}
default PageResult<SeckillActivityDO> selectPage(AppSeckillActivityPageReqVO pageReqVO, Integer status) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<SeckillActivityDO>()
.eqIfPresent(SeckillActivityDO::getStatus, status)
.apply(ObjectUtil.isNotNull(pageReqVO.getConfigId()), "FIND_IN_SET(" + pageReqVO.getConfigId() + ",config_ids) > 0"));
}
}

View File

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

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActivityPageReqVO;
@ -7,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.bargain.vo.BargainActi
import cn.iocoder.yudao.module.promotion.dal.dataobject.bargain.BargainActivityDO;
import javax.validation.Valid;
import java.util.List;
/**
* 砍价活动 Service 接口
@ -61,4 +63,19 @@ public interface BargainActivityService {
*/
PageResult<BargainActivityDO> getBargainActivityPage(BargainActivityPageReqVO pageReqVO);
/**
* 获取 APP 端活动分页数据
*
* @param pageReqVO 分页请求
* @return 砍价活动分页
*/
PageResult<BargainActivityDO> getBargainActivityAppPage(PageParam pageReqVO);
/**
* 获取 APP 端活动展示数据
*
* @param count 需要的数量
* @return
*/
List<BargainActivityDO> getBargainActivityAppList(Integer count);
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.service.bargain;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -113,9 +115,9 @@ public class BargainActivityServiceImpl implements BargainActivityService {
// 校验存在
BargainActivityDO activityDO = validateBargainActivityExists(id);
// 校验状态
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);
@ -139,4 +141,20 @@ public class BargainActivityServiceImpl implements BargainActivityService {
return bargainActivityMapper.selectPage(pageReqVO);
}
@Override
public PageResult<BargainActivityDO> getBargainActivityAppPage(PageParam pageReqVO) {
// 只查询进行中且在时间范围内的
return bargainActivityMapper.selectAppPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
}
@Override
public List<BargainActivityDO> getBargainActivityAppList(Integer count) {
if (count == null) {
count = 6;
}
PageResult<BargainActivityDO> result = bargainActivityMapper.selectAppPage(new PageParam().setPageSize(count), CommonStatusEnum.ENABLE.getStatus(), LocalDateTime.now());
return result.getList();
}
}

View File

@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.promotion.service.combination;
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.CombinationActivityPageReqVO;
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);
/**
* 更新拼图活动库存
* 校验是否满足拼团条件
*
* @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.spu.ProductSpuApi;
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.CombinationActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.combination.vo.activity.CombinationActivityUpdateReqVO;
@ -34,7 +33,6 @@ 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.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.SPU_NOT_EXISTS;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.*;
@ -88,7 +86,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
/**
* 校验拼团商品参与的活动是否存在冲突
*
* @param spuId 商品 SPU 编号
* @param spuId 商品 SPU 编号
* @param activityId 拼团活动编号
*/
private void validateProductConflict(Long spuId, Long activityId) {
@ -107,7 +105,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
/**
* 校验拼团商品是否都存在
*
* @param spuId 商品 SPU 编号
* @param spuId 商品 SPU 编号
* @param products 拼团商品
*/
private void validateProductExists(Long spuId, List<CombinationProductBaseVO> products) {
@ -152,7 +150,7 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
* 更新拼团商品
*
* @param activity 拼团活动
* @param products 该活动的最新商品配置
* @param products 该活动的最新商品配置
*/
private void updateCombinationProduct(CombinationActivityDO activity, List<CombinationProductBaseVO> products) {
// 第一步对比新老数据获得添加修改删除的列表
@ -217,35 +215,34 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
}
@Override
public void validateCombination(CombinationActivityUpdateStockReqDTO reqDTO) {
public void validateCombination(Long activityId, Long userId, Long skuId, Integer count) {
// 1.1 校验拼团活动是否存在
CombinationActivityDO activity = validateCombinationActivityExists(reqDTO.getActivityId());
CombinationActivityDO activity = validateCombinationActivityExists(activityId);
// 1.2 校验活动是否开启
if (ObjectUtil.equal(activity.getStatus(), CommonStatusEnum.DISABLE.getStatus())) {
throw exception(COMBINATION_ACTIVITY_STATUS_DISABLE);
}
// 1.3 校验是否超出单次限购数量
if (activity.getSingleLimitCount() < reqDTO.getCount()) {
if (activity.getSingleLimitCount() < count) {
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
}
// 2. 校验是否超出总限购数量
// TODO @puhui999userId 应该接口传递哈要保证 service 无状态
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(
getLoginUserId(), reqDTO.getActivityId());
// TODO @puhui999最好 if true return减少括号层数
if (CollUtil.isNotEmpty(recordList)) {
// 过滤出拼团成功的
// TODO @puhui999count 要不存一个在 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);
}
List<CombinationRecordDO> recordList = combinationRecordService.getRecordListByUserIdAndActivityId(userId, activityId);
if (CollUtil.isEmpty(recordList)) {
return;
}
// 过滤出拼团成功的
// TODO @puhui999count 要不存一个在 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);
}
}
}

View File

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

View File

@ -129,19 +129,10 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
}
// 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());
record.setNickname(user.getNickname());
record.setAvatar(user.getAvatar());
ProductSpuRespDTO spu = productSpuApi.getSpu(record.getSpuId());
record.setSpuName(spu.getName());
ProductSkuRespDTO sku = productSkuApi.getSku(record.getSkuId());
record.setPicUrl(sku.getPicUrl());
recordMapper.insert(record);
ProductSpuRespDTO spu = productSpuApi.getSpu(reqDTO.getSpuId());
ProductSkuRespDTO sku = productSkuApi.getSku(reqDTO.getSkuId());
recordMapper.insert(CombinationActivityConvert.INSTANCE.convert1(reqDTO, activity, user, spu, sku));
}
@Override
@ -154,20 +145,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
return recordMapper.selectListByUserIdAndActivityId(userId, activityId);
}
@Override
public void validateCombinationLimitCount(Long activityId, Integer count, Integer sumCount) {
// 1.1 校验拼团活动
CombinationActivityDO activity = combinationActivityService.validateCombinationActivityExists(activityId);
// 校验是否达到限购总限购标准
if ((sumCount + count) > activity.getTotalLimitCount()) {
throw exception(COMBINATION_RECORD_FAILED_TOTAL_LIMIT_COUNT_EXCEED);
}
// 单次购买是否达到限购标准
if (count > activity.getSingleLimitCount()) {
throw exception(COMBINATION_RECORD_FAILED_SINGLE_LIMIT_COUNT_EXCEED);
}
}
/**
* APP 端获取开团记录
*

View File

@ -1,10 +1,10 @@
package cn.iocoder.yudao.module.promotion.service.seckill;
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.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
@ -37,9 +37,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);
/**
* 关闭秒杀活动
@ -87,4 +89,20 @@ public interface SeckillActivityService {
*/
List<SeckillProductDO> getSeckillProductListByActivityId(Collection<Long> activityIds);
/**
* 通过活动时段获取秒杀活动
*
* @param ids 时段配置编号
* @return 秒杀活动列表
*/
List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids);
/**
* 通过活动时段获取秒杀活动
*
* @param pageReqVO 请求
* @return 秒杀活动列表
*/
PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO);
}

View File

@ -3,15 +3,16 @@ package cn.iocoder.yudao.module.promotion.service.seckill;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.api.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.SeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.seckillactivity.SeckillProductDO;
@ -147,32 +148,32 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
@Override
@Transactional(rollbackFor = Exception.class)
public void updateSeckillStock(SeckillActivityUpdateStockReqDTO updateStockReqDTO) {
public void updateSeckillStock(Long activityId, Long skuId, Integer count) {
// 1校验秒杀活动是否存在
SeckillActivityDO seckillActivity = getSeckillActivity(updateStockReqDTO.getActivityId());
SeckillActivityDO seckillActivity = getSeckillActivity(activityId);
// 1.1校验库存是否充足
if (seckillActivity.getTotalStock() < updateStockReqDTO.getCount()) {
if (seckillActivity.getTotalStock() < count) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
}
// 2获取活动商品
List<SeckillProductDO> products = getSeckillProductListByActivityId(updateStockReqDTO.getActivityId());
List<SeckillProductDO> products = getSeckillProductListByActivityId(activityId);
// 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检查活动商品库存是否充足
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) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
}
// 3更新活动商品库存
int updateCount = seckillProductMapper.updateActivityStock(product.getId(), updateStockReqDTO.getItem().getCount());
int updateCount = seckillProductMapper.updateActivityStock(product.getId(), count);
if (updateCount == 0) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
}
// 4更新活动库存
updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), updateStockReqDTO.getCount());
updateCount = seckillActivityMapper.updateActivityStock(seckillActivity.getId(), count);
if (updateCount == 0) {
throw exception(SECKILL_ACTIVITY_UPDATE_STOCK_FAIL);
}
@ -265,4 +266,15 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
return seckillProductMapper.selectListByActivityId(activityIds);
}
@Override
public List<SeckillActivityDO> getSeckillActivityListByConfigIds(Collection<Long> ids) {
return CollectionUtils.filterList(seckillActivityMapper.selectList(),
item -> CollectionUtils.anyMatch(item.getConfigIds(), ids::contains));
}
@Override
public PageResult<SeckillActivityDO> getSeckillActivityAppPageByConfigId(AppSeckillActivityPageReqVO pageReqVO) {
return seckillActivityMapper.selectPage(pageReqVO, CommonStatusEnum.ENABLE.getStatus());
}
}

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.sku.dto.ProductSkuRespDTO;
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.seckill.dto.SeckillActivityUpdateStockReqDTO;
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.product.property.ProductPropertyValueDetailRespVO;
@ -279,15 +277,9 @@ public interface TradeOrderConvert {
return new BrokerageAddReqBO().setBizId(String.valueOf(item.getId())).setSourceUserId(item.getUserId())
.setBasePrice(item.getPayPrice() * item.getCount())
.setTitle(StrUtil.format("{}成功购买{}", user.getNickname(), item.getSpuName()))
.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);
@Mappings({

View File

@ -184,9 +184,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Transactional(rollbackFor = Exception.class)
public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
// 1执行订单创建前置处理器
// TODO @puhui999最好也抽个 beforeOrderCreate 方法
// TODO @puhui999最好也抽个 beforeOrderCreate 方法不要 BO 各自处理参数岂不美哉
TradeBeforeOrderCreateReqBO beforeOrderCreateReqBO = TradeOrderConvert.INSTANCE.convert(createReqVO);
beforeOrderCreateReqBO.setOrderType(validateActivity(createReqVO));
beforeOrderCreateReqBO.setUserId(userId);
beforeOrderCreateReqBO.setCount(getSumValue(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCount, Integer::sum));
// TODO @puhui999这里有个纠结点handler 的定义是只处理指定类型的订单的拓展逻辑还是通用的 handler类似可以处理优惠劵等等
tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(beforeOrderCreateReqBO));
@ -730,7 +731,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
}
// TODO 活动相关库存回滚需要活动 id活动 id 怎么获取app 端能否传过来
tradeOrderHandlers.forEach(handler -> handler.rollbackStock());
tradeOrderHandlers.forEach(handler -> handler.rollback());
// 2.回滚库存
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 lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
// TODO 芋艿在想想这些参数的定义
@ -34,25 +33,16 @@ public class TradeBeforeOrderCreateReqBO {
@Schema(description = "砍价活动编号", example = "123")
private Long bargainActivityId;
@NotNull(message = "SPU 编号不能为空")
private Long spuId;
@NotNull(message = "SKU 编号活动商品不能为空")
private Long skuId;
@NotNull(message = "用户编号不能为空")
private Long userId;
@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

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

View File

@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.trade.service.order.handler;
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.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
@ -20,7 +20,7 @@ import javax.annotation.Resource;
public class TradeCombinationHandler implements TradeOrderHandler {
@Resource
private CombinationApi combinationApi;
private CombinationActivityApi combinationActivityApi;
@Resource
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
@ -42,7 +42,7 @@ public class TradeCombinationHandler implements TradeOrderHandler {
}
@Override
public void rollbackStock() {
public void rollback() {
}

View File

@ -25,8 +25,8 @@ public interface TradeOrderHandler {
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.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.service.order.bo.TradeAfterOrderCreateReqBO;
import cn.iocoder.yudao.module.trade.service.order.bo.TradeBeforeOrderCreateReqBO;
@ -28,7 +27,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
return;
}
seckillActivityApi.updateSeckillStock(TradeOrderConvert.INSTANCE.convert(reqBO));
seckillActivityApi.updateSeckillStock(reqBO.getSeckillActivityId(), reqBO.getSkuId(), reqBO.getCount());
}
@Override
@ -37,7 +36,7 @@ public class TradeSeckillHandler implements TradeOrderHandler {
}
@Override
public void rollbackStock() {
public void rollback() {
}