|
|
@@ -1,6 +1,5 @@
|
|
|
package com.ruoyi.shop.marketing.seckill.service.impl;
|
|
|
|
|
|
-import cn.hutool.core.bean.BeanUtil;
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
@@ -10,6 +9,9 @@ import com.ruoyi.common.core.domain.PageQuery;
|
|
|
import com.ruoyi.common.core.page.TableDataInfo;
|
|
|
import com.ruoyi.common.exception.ServiceException;
|
|
|
import com.ruoyi.common.utils.BeanCopyUtils;
|
|
|
+import com.ruoyi.common.utils.MathUtils;
|
|
|
+import com.ruoyi.common.utils.redis.RedisUtils;
|
|
|
+import com.ruoyi.common.utils.redis.SemaphoreTool;
|
|
|
import com.ruoyi.shop.enums.PriceType;
|
|
|
import com.ruoyi.shop.marketing.seckill.domain.SeckillActivityProduct;
|
|
|
import com.ruoyi.shop.marketing.seckill.domain.bo.SeckillActivityProductBo;
|
|
|
@@ -19,8 +21,9 @@ import com.ruoyi.shop.marketing.seckill.mapper.SeckillActivityProductMapper;
|
|
|
import com.ruoyi.shop.marketing.seckill.service.ISeckillActivityProductService;
|
|
|
import com.ruoyi.shop.marketing.seckill.service.ISeckillActivityService;
|
|
|
import com.ruoyi.shop.product.domain.Product;
|
|
|
-import com.ruoyi.shop.product.domain.vo.SkuTableItem;
|
|
|
+import com.ruoyi.shop.product.domain.bo.ProductSkuSetBo;
|
|
|
import com.ruoyi.shop.product.service.IProductService;
|
|
|
+import com.ruoyi.shop.product.service.IProductSkuSetService;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import org.springframework.context.annotation.Lazy;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
@@ -44,9 +47,13 @@ public class SeckillActivityProductServiceImpl implements ISeckillActivityProduc
|
|
|
|
|
|
private final SeckillActivityProductMapper baseMapper;
|
|
|
private final IProductService productService;
|
|
|
+ private final SemaphoreTool semaphoreTool;
|
|
|
@Lazy
|
|
|
@Resource
|
|
|
private ISeckillActivityService seckillActivityService;
|
|
|
+ @Lazy
|
|
|
+ @Resource
|
|
|
+ private IProductSkuSetService productSkuSetService;
|
|
|
|
|
|
/**
|
|
|
* 查询秒杀活动商品分页
|
|
|
@@ -127,6 +134,65 @@ public class SeckillActivityProductServiceImpl implements ISeckillActivityProduc
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
@Override
|
|
|
public Boolean insertByBo(SeckillActivityProductBo bo) {
|
|
|
+ Product product = verifyBo(bo);
|
|
|
+ //如果该秒杀活动上架了该商品,则是修改
|
|
|
+ SeckillActivityProduct seckillActivityProduct = this.baseMapper.selectOne(
|
|
|
+ new LambdaQueryWrapper<SeckillActivityProduct>()
|
|
|
+ .eq(SeckillActivityProduct::getProductId, bo.getProductId())
|
|
|
+ .eq(SeckillActivityProduct::getSeckillId, bo.getSeckillId())
|
|
|
+ .last("limit 1")
|
|
|
+ );
|
|
|
+ if (seckillActivityProduct == null) {
|
|
|
+ seckillActivityProduct = new SeckillActivityProduct();
|
|
|
+ }
|
|
|
+ SeckillActivityProduct add = BeanCopyUtils.copy(bo, seckillActivityProduct);
|
|
|
+ add.setSkuTableValue(product.getSkuTable());
|
|
|
+ //可售数量+初始化销量>=已售数量
|
|
|
+ if ((add.getRealStockTotal() + add.getInitSaleNum()) < add.getResultSaleNum()) {
|
|
|
+ throw new ServiceException(SeckillActivityProductExceptionEnum.SALE_EXCEPTION);
|
|
|
+ }
|
|
|
+ //保存
|
|
|
+ baseMapper.insertOrUpdate(add);
|
|
|
+ //保存秒杀活动sku
|
|
|
+ List<ProductSkuSetBo> seckillSkuList = bo.getProductSkuSetList();
|
|
|
+ productSkuSetService.batchSaveBySeckill(add, product, seckillSkuList);
|
|
|
+ //更新秒杀活动商品的最大、最小价格
|
|
|
+ //最小价格
|
|
|
+ BigDecimal minPrice = seckillSkuList.stream().map(ProductSkuSetBo::getSalePrice).min(BigDecimal::compareTo).orElseGet(() -> BigDecimal.ZERO);
|
|
|
+ //最大价格
|
|
|
+ BigDecimal maxPrice = seckillSkuList.stream().map(ProductSkuSetBo::getSalePrice).max(BigDecimal::compareTo).orElseGet(() -> BigDecimal.ZERO);
|
|
|
+ add.setMinPrice(minPrice);
|
|
|
+ add.setMaxPrice(maxPrice);
|
|
|
+ BigDecimal minSalePrice = seckillSkuList.stream().map(ProductSkuSetBo::getOriginalSalePrice).min(BigDecimal::compareTo).orElseGet(() -> BigDecimal.ZERO);
|
|
|
+ //最大价格
|
|
|
+ BigDecimal maxSalePrice = seckillSkuList.stream().map(ProductSkuSetBo::getOriginalSalePrice).max(BigDecimal::compareTo).orElseGet(() -> BigDecimal.ZERO);
|
|
|
+ //最小销售价(原商品的最小销售价)
|
|
|
+ add.setMinSalePrice(minSalePrice);
|
|
|
+ //最大销售价
|
|
|
+ add.setMaxSalePrice(maxSalePrice);
|
|
|
+ add.loadProductSkuSetList();
|
|
|
+ //3.2计算销量和库存
|
|
|
+ add.computeResultSaleAndResidueStock();
|
|
|
+ baseMapper.updateById(add);
|
|
|
+ //创建信号量
|
|
|
+ createAndSetSemaphore(add);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void createAndSetSemaphore(SeckillActivityProduct activityProduct) {
|
|
|
+ String key = getSemaphoreKey(activityProduct.getSeckillId(), activityProduct.getId(), activityProduct.getProductId());
|
|
|
+ Integer num = RedisUtils.getCacheObject(key);
|
|
|
+ if (num != null) {
|
|
|
+ RedisUtils.deleteObject(key);
|
|
|
+ }
|
|
|
+ semaphoreTool.setRSemaphorePermits(key, activityProduct.getResidueStockTotal());
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getSemaphoreKey(Long activityId, Long activityProductId, Long productId) {
|
|
|
+ return "seckill:activityId:" + activityId + "activityProductId:" + activityProductId + "_productId:" + productId;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Product verifyBo(SeckillActivityProductBo bo) {
|
|
|
//1、校验商品是否是该商家的
|
|
|
Product product = productService.getByBusinessIdAndId(bo.getBusinessId(), bo.getProductId());
|
|
|
//2、校验秒杀活动是否是该商家的
|
|
|
@@ -149,27 +215,21 @@ public class SeckillActivityProductServiceImpl implements ISeckillActivityProduc
|
|
|
throw new ServiceException(SeckillActivityProductExceptionEnum.REAL_STOCK_TOTAL_LT_INIT_SALE_NUM);
|
|
|
}
|
|
|
//4、校验活动价格
|
|
|
- List<SkuTableItem> skuTableValue = bo.getSkuTableValue();
|
|
|
- if (CollUtil.isNotEmpty(skuTableValue)) {
|
|
|
- for (SkuTableItem sku : skuTableValue) {
|
|
|
-// //活动价格不能小于0
|
|
|
-// if (sku.getActivityPrice().compareTo(BigDecimal.ZERO) < 0) {
|
|
|
-// throw new RRException(MarketingException.ACTIVITY_PRICE_OUT_OF_RANGE);
|
|
|
-// }
|
|
|
-// //活动价格需要小于原价
|
|
|
-// if (MathUtils.subtract(sku.getActivityPrice(), sku.getSalePrice())
|
|
|
-// .compareTo(BigDecimal.ZERO) >= 0) {
|
|
|
-// throw new RRException(MarketingException.ACTIVITY_PRICE_LT_SALE_PRICE);
|
|
|
-// }
|
|
|
+ List<ProductSkuSetBo> productSkuSetList = bo.getProductSkuSetList();
|
|
|
+ if (CollUtil.isNotEmpty(productSkuSetList)) {
|
|
|
+ for (ProductSkuSetBo setBo : productSkuSetList) {
|
|
|
+ //活动价格不能小于0
|
|
|
+ if (setBo.getSalePrice().compareTo(BigDecimal.ZERO) < 0) {
|
|
|
+ throw new ServiceException(SeckillActivityProductExceptionEnum.ACTIVITY_PRICE_OUT_OF_RANGE);
|
|
|
+ }
|
|
|
+ //活动价格需要小于原价
|
|
|
+ if (MathUtils.subtract(setBo.getSalePrice(), setBo.getOriginalSalePrice())
|
|
|
+ .compareTo(BigDecimal.ZERO) >= 0) {
|
|
|
+ throw new ServiceException(SeckillActivityProductExceptionEnum.ACTIVITY_PRICE_LT_SALE_PRICE);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- SeckillActivityProduct add = BeanUtil.toBean(bo, SeckillActivityProduct.class);
|
|
|
- validEntityBeforeSave(add);
|
|
|
- boolean flag = baseMapper.insert(add) > 0;
|
|
|
- if (flag) {
|
|
|
- bo.setId(add.getId());
|
|
|
- }
|
|
|
- return flag;
|
|
|
+ return product;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -201,12 +261,33 @@ public class SeckillActivityProductServiceImpl implements ISeckillActivityProduc
|
|
|
* @param ids 需要删除的秒杀活动商品主键
|
|
|
* @return 结果
|
|
|
*/
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
@Override
|
|
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
|
|
- if(isValid){
|
|
|
+ if (isValid) {
|
|
|
//TODO 做一些业务上的校验,判断是否需要校验
|
|
|
}
|
|
|
- return baseMapper.deleteBatchIds(ids) > 0;
|
|
|
+ for (Long id : ids) {
|
|
|
+ //秒杀活动只要开始了,就不能被删除
|
|
|
+// SeckillActivityGoods goods = this.loadActivityGoodsById(id, true);
|
|
|
+// SeckillActivity activity = seckillActivityService.getById(goods.getSeckillId());
|
|
|
+// Date startDate = DateUtils.stringToDate(DateCustomUtils.dateToString(activity.getStartTime()) + " " + activity.getStartHour());
|
|
|
+// Date endDate = DateUtils.stringToDate(DateCustomUtils.dateToString(activity.getEndTime()) + " " + activity.getEndHour());
|
|
|
+// long timeMillis = System.currentTimeMillis();
|
|
|
+// if (timeMillis > startDate.getTime() && timeMillis <= endDate.getTime()) {
|
|
|
+// throw new RRException(MarketingException.SECKILL_ACTIVITY_START);
|
|
|
+// }
|
|
|
+//
|
|
|
+// //1、删除秒杀活动商品
|
|
|
+// this.baseMapper.deleteById(id);
|
|
|
+//
|
|
|
+// //2、删除秒杀活动商品sku
|
|
|
+// seckillGoodsSkuService.deleteBySeckillGoodsId(id);
|
|
|
+//
|
|
|
+// //删除秒杀的信号量
|
|
|
+// redisUtils.delete(SeckillActivityGoodsService.getSemaphoreKey(goods.getSeckillId(), goods.getId(), goods.getGoodsId()));
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
@Override
|