拼团和秒杀活动获取剩余购买次数接口

This commit is contained in:
XinWei 2024-10-12 09:35:10 +08:00
parent 6c1b724d93
commit 8266266387
10 changed files with 139 additions and 8 deletions

View File

@ -6,14 +6,20 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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;
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.SeckillValidateJoinRespDTO;
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityDetailRespVO; import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityPurchasesTimesReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO; import cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity.AppCombinationActivityRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillPurchasesTimesReqVO;
import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert; import cn.iocoder.yudao.module.promotion.convert.combination.CombinationActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationProductDO;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService; import cn.iocoder.yudao.module.promotion.service.combination.CombinationActivityService;
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -60,7 +66,8 @@ public class AppCombinationActivityController {
@Resource @Resource
private ProductSpuApi spuApi; private ProductSpuApi spuApi;
@Resource
private TradeOrderApi tradeOrderApi;
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "获得拼团活动列表", description = "用于小程序首页") @Operation(summary = "获得拼团活动列表", description = "用于小程序首页")
@Parameter(name = "count", description = "需要展示的数量", example = "6") @Parameter(name = "count", description = "需要展示的数量", example = "6")
@ -129,5 +136,14 @@ public class AppCombinationActivityController {
List<CombinationProductDO> products = activityService.getCombinationProductsByActivityId(activity.getId()); List<CombinationProductDO> products = activityService.getCombinationProductsByActivityId(activity.getId());
return success(CombinationActivityConvert.INSTANCE.convert3(activity, products)); return success(CombinationActivityConvert.INSTANCE.convert3(activity, products));
} }
@GetMapping("/getPurchaseTimes")
@Operation(summary = "获得剩余拼团购买次数")
public CommonResult<Integer> getSeckillActivityPage(AppCombinationActivityPurchasesTimesReqVO reqVO) {
// 1. 获取总限购数量
CombinationActivityDO combinationActivity = activityService.getCombinationActivity(reqVO.getActivityId());
// 2. 获取已购买数量
int seckillProductCount = tradeOrderApi.getCombinationProductCount(reqVO.getUserId(), reqVO.getActivityId());
// 3. 总次数减去下单过的次数 得到剩余次数
return success(Math.max(combinationActivity.getTotalLimitCount() - seckillProductCount, 0));
}
} }

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.promotion.controller.app.combination.vo.activity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.Valid;
@Schema(description = "用户 App - 拼团剩余购买次数 Request VO")
@Data
@Valid
public class AppCombinationActivityPurchasesTimesReqVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED)
private Long userId;
@Schema(description = "拼团活动编号", example = "1024")
private Long activityId;
}

View File

@ -7,18 +7,19 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils; import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
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.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO; import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.*;
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.convert.seckill.seckillactivity.SeckillActivityConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
@ -42,6 +43,7 @@ import java.time.LocalTime;
import java.util.*; import java.util.*;
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.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache; import static cn.iocoder.yudao.framework.common.util.cache.CacheUtils.buildAsyncReloadingCache;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@ -77,6 +79,12 @@ public class AppSeckillActivityController {
@Resource @Resource
private ProductSpuApi spuApi; private ProductSpuApi spuApi;
@Resource
private ProductSkuApi skuApi;
@Resource
private TradeOrderApi tradeOrderApi;
@GetMapping("/get-now") @GetMapping("/get-now")
@Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用") @Operation(summary = "获得当前秒杀活动", description = "获取当前正在进行的活动,提供给首页使用")
public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() { public CommonResult<AppSeckillActivityNowRespVO> getNowSeckillActivity() {
@ -120,7 +128,8 @@ public class AppSeckillActivityController {
@Operation(summary = "获得现在进行的秒杀活动分页") @Operation(summary = "获得现在进行的秒杀活动分页")
public CommonResult<List<ProductSpuRespDTO>> getSeckillActivitySupList(@RequestParam(name = "count", defaultValue = "3") Integer count) { public CommonResult<List<ProductSpuRespDTO>> getSeckillActivitySupList(@RequestParam(name = "count", defaultValue = "3") Integer count) {
AppSeckillActivityPageReqVO pageReqVO = new AppSeckillActivityPageReqVO(); AppSeckillActivityPageReqVO pageReqVO = new AppSeckillActivityPageReqVO();
Page<SeckillActivityDO> page = new Page<>(1, 3);; Page<SeckillActivityDO> page = new Page<>(1, 3);
;
if (count != null && count != 0) { if (count != null && count != 0) {
page = new Page<>(1, count); page = new Page<>(1, count);
} }
@ -210,4 +219,14 @@ public class AppSeckillActivityController {
return success(SeckillActivityConvert.INSTANCE.convert3(activity, productList, startTime, endTime)); return success(SeckillActivityConvert.INSTANCE.convert3(activity, productList, startTime, endTime));
} }
@GetMapping("/getPurchaseTimes")
@Operation(summary = "获得剩余秒杀购买次数")
public CommonResult<Integer> getSeckillActivityPage(AppSeckillPurchasesTimesReqVO reqVO) {
// 1. 获取总限购数量
SeckillActivityDO seckillActivity = activityService.getSeckillActivity(reqVO.getActivityId());
// 2. 获取已购买数量
int seckillProductCount = tradeOrderApi.getSeckillProductCount(reqVO.getUserId(), reqVO.getActivityId());
// 3. 总次数减去下单过的次数 得到剩余次数
return success(Math.max(seckillActivity.getTotalLimitCount() - seckillProductCount, 0));
}
} }

View File

@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@Schema(description = "用户 App - 秒杀剩余购买次数 Request VO")
@Data
@Valid
public class AppSeckillPurchasesTimesReqVO {
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED)
private Long userId;
@Schema(description = "秒杀活动编号", example = "1024")
private Long activityId;
}

View File

@ -37,4 +37,19 @@ public interface TradeOrderApi {
*/ */
void cancelPaidOrder(Long userId, Long orderId); void cancelPaidOrder(Long userId, Long orderId);
/**
* 获取已经使用的秒杀次数
* @param userId 用户编号
* @param activityId 秒杀活动编号
* @return java.lang.Integer
*/
Integer getSeckillProductCount(Long userId, Long activityId);
/**
* 获取已经使用的拼团次数
* @param userId 用户编号
* @param activityId 拼团活动编号
* @return java.lang.Integer
*/
Integer getCombinationProductCount(Long userId, Long activityId);
} }

View File

@ -40,4 +40,14 @@ public class TradeOrderApiImpl implements TradeOrderApi {
tradeOrderUpdateService.cancelPaidOrder(userId, orderId); tradeOrderUpdateService.cancelPaidOrder(userId, orderId);
} }
@Override
public Integer getSeckillProductCount(Long userId, Long activityId) {
return tradeOrderQueryService.getSeckillProductCount(userId, activityId);
}
@Override
public Integer getCombinationProductCount(Long userId, Long activityId) {
return tradeOrderQueryService.getCombinationProductCount(userId, activityId);
}
} }

View File

@ -124,4 +124,9 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
); );
} }
default List<TradeOrderDO> selectListByUserIdAndCombinationActivityId(Long userId, Long activityId){
LambdaQueryWrapperX<TradeOrderDO> wrapperX = new LambdaQueryWrapperX<>();
wrapperX.eq(TradeOrderDO::getUserId, userId).eq(TradeOrderDO::getSeckillActivityId, activityId);
return selectList(wrapperX);
}
} }

View File

@ -155,4 +155,12 @@ public interface TradeOrderQueryService {
*/ */
List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds); List<TradeOrderItemDO> getOrderItemListByOrderId(Collection<Long> orderIds);
/**
* 在指定拼团活动下用户购买的商品数量
*
* @param userId 用户编号
* @param activityId 活动编号
* @return 拼团商品数量
*/
Integer getCombinationProductCount(Long userId, Long activityId);
} }

View File

@ -247,6 +247,18 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
return tradeOrderItemMapper.selectListByOrderId(orderIds); return tradeOrderItemMapper.selectListByOrderId(orderIds);
} }
@Override
public Integer getCombinationProductCount(Long userId, Long activityId) {
// 获得订单列表
List<TradeOrderDO> orders = tradeOrderMapper.selectListByUserIdAndCombinationActivityId(userId, activityId);
orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉已取消的订单
if (CollUtil.isEmpty(orders)) {
return 0;
}
// 获得订单项列表
return tradeOrderItemMapper.selectProductSumByOrderId(convertSet(orders, TradeOrderDO::getId));
}
/** /**
* 获得自身的代理对象解决 AOP 生效问题 * 获得自身的代理对象解决 AOP 生效问题
* *

View File

@ -51,7 +51,10 @@ public class TradePriceServiceImpl implements TradePriceService {
// 2.1 计算价格 // 2.1 计算价格
TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper
.buildCalculateResp(calculateReqBO, spuList, skuList); .buildCalculateResp(calculateReqBO, spuList, skuList);
priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); // priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO));
for (TradePriceCalculator calculator : priceCalculators) {
calculator.calculate(calculateReqBO, calculateRespBO);
}
// 2.2 如果最终支付金额小于等于 0则抛出业务异常 // 2.2 如果最终支付金额小于等于 0则抛出业务异常
if (calculateRespBO.getPrice().getPayPrice() <= 0) { if (calculateRespBO.getPrice().getPayPrice() <= 0) {
log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]", log.error("[calculatePrice][价格计算不正确,请求 calculateReqDTO({}),结果 priceCalculate({})]",