记得上下班打卡 | git大法好,push需谨慎

Commit 73369bc4 authored by 胡佳晨's avatar 胡佳晨

盲盒下单 判断逻辑完成

parent d246f201
......@@ -266,7 +266,7 @@ public class GoblinMixServiceImpl implements IGoblinMixService {
if (isHit && hitRatioCount.doubleValue() < 100.00 && map.size() > 0) {
nftBoxUtils.arrangeHitRatioMap(map, hitRatioCount);
}
Map<String, Integer> skuMap = nftBoxUtils.getSkuHitRatio(stock, map);
Map<String, Integer> skuMap = nftBoxUtils.getSkuHitRatio(stock * item.getCount(), map);
for (String key : skuMap.keySet()) {
Integer stockNum = skuMap.get(key);
//库存
......@@ -283,12 +283,12 @@ public class GoblinMixServiceImpl implements IGoblinMixService {
}
} else {
//库存
int skuStock = redisUtils.decrSkuStock(null, skuId, stock);
int skuStock = redisUtils.decrSkuStock(null, skuId, stock * item.getCount());
if (skuStock < 0) {
redisUtils.incrSkuStock(null, skuId, stock);
redisUtils.incrSkuStock(null, skuId, stock * item.getCount());
errorNameList.add(item.getSkuName());
} else {
redisUtils.setSkuStock(mixId, skuId, stock);
redisUtils.setSkuStock(mixId, skuId, stock * item.getCount());
sucSkuId.add(skuId);
}
}//普通商品
......
......@@ -1756,7 +1756,7 @@ public class GoblinMongoUtils {
public HashMap<String, Object> getGoblinMixListVo(String name, String uid, Integer pageNum) {
int pageSize = 20;
Criteria criteria = Criteria.where("uid").is(uid);
Criteria criteria = Criteria.where("userId").is(uid);
if (name != null && !name.equals("")) {
criteria = criteria.and("name").regex("^.*" + name + ".*$");
}
......
package com.liquidnet.service.order.service.impl;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.constant.NftAccStatusEnum;
import com.liquidnet.service.goblin.dto.GoblinUserNftAccInfoVo;
import com.liquidnet.service.goblin.dto.manage.MixOrderParam;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinMixDetailsItemVo;
import com.liquidnet.service.goblin.dto.vo.GoblinMixDetailsVo;
import com.liquidnet.service.goblin.dto.vo.GoblinPayInnerResultVo;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.param.SyncOrderParam;
import com.liquidnet.service.goblin.service.IMixOrderService;
import com.liquidnet.service.order.utils.*;
......@@ -49,6 +47,9 @@ public class MixOrderServiceImpl implements IMixOrderService {
GoblinMixDetailsVo mixVo = redisUtils.getMixDetails(param.getMixId());
String mixId = mixVo.getMixId();
String mobile = StringUtils.defaultString(((String) CurrentUtil.getTokenClaims().get(CurrentUtil.TOKEN_MOBILE)), "");
List<String> canBuyIds = CollectionUtil.linkedListString();//有库存的id
String boxSkuId = "";//盲盒种的skuid
String stockSkuId = ""; // 盲盒id
//判断 活动状态
LocalDateTime st = LocalDateTime.parse(mixVo.getTimeStart(), DTF_YMD_HMS);
LocalDateTime et = LocalDateTime.parse(mixVo.getTimeEnd(), DTF_YMD_HMS);
......@@ -72,7 +73,42 @@ public class MixOrderServiceImpl implements IMixOrderService {
List<GoblinGoodsSkuInfoVo> skuInfoList = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
List<GoblinGoodsSkuInfoVo> nftInfoList = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
for (GoblinMixDetailsItemVo itemVo : mixVo.getItem()) {
GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(itemVo.getSkuId());
String skuId = itemVo.getSkuId();
GoblinGoodsSkuInfoVo skuInfoVo = redisUtils.getGoodsSkuInfoVo(skuId);
//库存处理
if (skuInfoVo.getUnbox().equals("1")) {//盲盒
GoblinGoodsInfoVo spuInfoVo = redisUtils.getGoodsInfoVo(skuInfoVo.getSpuId());
List<String> skuIdList = spuInfoVo.getSkuIdList();
if (CollectionUtil.isEmpty(skuIdList)) {
return ResponseDto.failure("该商品SPU不存在~");
} else {
GoblinGoodsSkuInfoVo boxSkuInfo = nftOrderUtils.lotteryDraw(skuIdList, itemVo.getCount(), nt, null);
if (null == boxSkuInfo) {
return ResponseDto.failure("盲盒库存不足啦~");
} else {
canBuyIds.add(boxSkuInfo.getSkuId() + "," + itemVo.getCount());
}
boxSkuId = skuInfoVo.getSkuId();
stockSkuId = boxSkuId;
}
} else {//正常
if (skuInfoVo.getSkuType() == 1) {
stockSkuId = skuId;
}
int stock = redisUtils.decrSkuStock(mixId, skuId, itemVo.getCount());
if (stock < 0) {
redisUtils.incrSkuStock(mixId, skuId, itemVo.getCount());
for (String canBuyId : canBuyIds) {
String[] data = canBuyId.split(",");
String skuIdSingle = data[0];
int count = Integer.parseInt(data[1]);
redisUtils.incrSkuStock(mixId, skuIdSingle, count);
}
return ResponseDto.failure("库存不足");
} else {
canBuyIds.add(skuId + "," + itemVo.getCount());
}
}
if (skuInfoVo.getSkuType() == 0) {
skuInfoList.add(skuInfoVo);
} else if (skuInfoVo.getSkuType() == 1) {
......@@ -85,11 +121,10 @@ public class MixOrderServiceImpl implements IMixOrderService {
if (nftInfoList.size() > 0) {
GoblinUserNftAccInfoVo openAccountInfo = redisUtils.getOpenAccountInfo(uid);
if (null == openAccountInfo || !NftAccStatusEnum.StatusAcc.SUCCESS.getCode().equals(openAccountInfo.getCode())) {
return ResponseDto.failure("您还未开通数字账户");
return ResponseDto.failure("您还未开通数字账户");
}
}
//库存处理
return null;
}
......
......@@ -18,10 +18,10 @@ import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
@Component
@Slf4j
......@@ -86,6 +86,7 @@ public class GoblinNftOrderUtils {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_ID_OF_CODE.concat(orderCode);
redisUtil.set(redisKey, orderId);
}
// code换id
public String getNftOrderIdOfCode(String orderCode) {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_NFT_ORDER_ID_OF_CODE.concat(orderCode);
......@@ -163,17 +164,19 @@ public class GoblinNftOrderUtils {
return (GoblinNftExCodeVo) obj;
}
}
public void setGoblinNftExCodeVo(GoblinNftExCodeVo codeVo) {
String redisKey = GoblinRedisConst.ACTIVITY_SKU_CODE.concat(codeVo.getCode());
redisUtil.set(redisKey, codeVo);
}
public int incrExCountByUid(String uid, String skuId, String activityId, int number) {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId+':').concat(skuId+':').concat(uid);
String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId + ':').concat(skuId + ':').concat(uid);
return (int) redisUtil.incr(redisKey, number);
}
public int decrExCountByUid(String uid, String skuId, String activityId, int number) {
String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId+':').concat(skuId+':').concat(uid);
String redisKey = GoblinRedisConst.REDIS_GOBLIN_EX_BUY_COUNT.concat(activityId + ':').concat(skuId + ':').concat(uid);
return (int) redisUtil.decr(redisKey, number);
}
......@@ -185,10 +188,11 @@ public class GoblinNftOrderUtils {
if (obj == null) {
return false;
} else {
GoblinGoodsAnticipateValueVo anticipateValueVo = (GoblinGoodsAnticipateValueVo)obj;
GoblinGoodsAnticipateValueVo anticipateValueVo = (GoblinGoodsAnticipateValueVo) obj;
return anticipateValueVo.getType() != 1;
}
}
// 是否预约过 没开启true
public boolean getUserAboutAut(String skuId, String uid) {
boolean valueBySkuId = getValueBySkuId(skuId);
......@@ -400,37 +404,37 @@ public class GoblinNftOrderUtils {
}
/**
* private int skuType 商品类型[0-常规|1-数字藏品]
* private String status 审核状态[0-初始编辑|1-审核中|2-审核不通过|3-审核通过];
* private String shelvesStatus 单品上架状态[0-待上架|1-下架|2-违规|3-上架];
* private String skuAppear 是否隐藏[0-默认展示|1-隐藏]; 隐藏款 拼参数可购买 盲盒可抽
* private String delFlg 删除标记[0-未删除|1-删除];
*
* private LocalDateTime saleStartTime 开售时间;
* private LocalDateTime saleStopTime 停售时间 预留 暂时不做处理;
* private String soldoutStatus 是否售罄[0-否|1-是];
*
* private String skuCanbuy 是否购买[0-否|1-是] 这个用来预览 前端自己判断;
*
* Integer upchain NFT上传声明状态[0-待上传|1-已声明|2-声明失败|9-声明中]
*
* 根据概率判断是否过滤当前sku 没设置概率或者设置了的返回true
*
* String unbox; 是否盲盒[0-否|1-是]
* private int skuType 商品类型[0-常规|1-数字藏品]
* private String status 审核状态[0-初始编辑|1-审核中|2-审核不通过|3-审核通过];
* private String shelvesStatus 单品上架状态[0-待上架|1-下架|2-违规|3-上架];
* private String skuAppear 是否隐藏[0-默认展示|1-隐藏]; 隐藏款 拼参数可购买 盲盒可抽
* private String delFlg 删除标记[0-未删除|1-删除];
* <p>
* private LocalDateTime saleStartTime 开售时间;
* private LocalDateTime saleStopTime 停售时间 预留 暂时不做处理;
* private String soldoutStatus 是否售罄[0-否|1-是];
* <p>
* private String skuCanbuy 是否购买[0-否|1-是] 这个用来预览 前端自己判断;
* <p>
* Integer upchain NFT上传声明状态[0-待上传|1-已声明|2-声明失败|9-声明中]
* <p>
* 根据概率判断是否过滤当前sku 没设置概率或者设置了的返回true
* <p>
* String unbox; 是否盲盒[0-否|1-是]
*/
// 获取盲盒下藏品的库存 各种状态下不能算库存的排除掉
public int getSkuAllStatusStock(String listId, GoblinGoodsSkuInfoVo info) {
if (
info != null
info != null
// && LocalDateTime.now().isAfter(info.getSaleStartTime())
&& (null == info.getSoldoutStatus() || info.getSoldoutStatus().equals("0"))
&& (null == info.getSkuCanbuy() || info.getSkuCanbuy().equals("1"))
&& (null == info.getHitRatio() || info.getHitRatio().compareTo(BigDecimal.ZERO) > 0)
&& (null == info.getSoldoutStatus() || info.getSoldoutStatus().equals("0"))
&& (null == info.getSkuCanbuy() || info.getSkuCanbuy().equals("1"))
&& (null == info.getHitRatio() || info.getHitRatio().compareTo(BigDecimal.ZERO) > 0)
) {// 可以返回库存
// 外面只有盲盒才能请求进来 里面只有不是分批购才判断盲盒里藏品的开售时间
if (null == listId) {
// if (LocalDateTime.now().isAfter(info.getSaleStartTime())) {
return goblinRedisUtils.getSkuStock(listId, info.getSkuId());
return goblinRedisUtils.getSkuStock(listId, info.getSkuId());
// } else {
// return 0;
// }
......@@ -441,16 +445,17 @@ public class GoblinNftOrderUtils {
return 0;
}
}
// 各种状态下判断藏品是否可以展示
public boolean getSkuAllStatusShow(GoblinGoodsSkuInfoVo info) {
if (
info != null
&& info.getSkuType() == 1
&& info.getStatus().equals("3")
&& info.getShelvesStatus().equals("3")
info != null
&& info.getSkuType() == 1
&& info.getStatus().equals("3")
&& info.getShelvesStatus().equals("3")
// && (info.getSkuAppear() == null || info.getSkuAppear().equals("0"))
&& info.getDelFlg().equals("0")
&& ((info.getUnbox().equals("0") && info.getUpchain() == 1) || info.getUnbox().equals("1"))
&& info.getDelFlg().equals("0")
&& ((info.getUnbox().equals("0") && info.getUpchain() == 1) || info.getUnbox().equals("1"))
) {
return true;
} else {
......@@ -458,4 +463,110 @@ public class GoblinNftOrderUtils {
}
}
public GoblinGoodsSkuInfoVo lotteryDraw(List<String> skuIdList, int number, LocalDateTime nowTime, String listId) {
// private HashMap<String, Object> lotteryDraw(List<String> skuIdList, int number, LocalDateTime nowTime) {
try {
ArrayList<GoblinGoodsSkuInfoVo> skuInfoVos = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
// ArrayList<String> listIds = ObjectUtil.cloneArrayListString();
for (String kid : skuIdList) {
HashMap<String, Object> map = goblinRedisUtils.getGoodsSkuInfoVo(nowTime, kid);
GoblinGoodsSkuInfoVo skuInfoVo = (GoblinGoodsSkuInfoVo) map.get("vo");
// String listId = (String) map.get("listId");
// 是盲盒的扔掉
if (skuInfoVo.getUnbox().equals("1")) {
continue;
}
// 不能购买的 没库存的 概率是0的 过滤
if (getSkuAllStatusShow(skuInfoVo) && getSkuAllStatusStock(listId, skuInfoVo) > 0) {
skuInfoVos.add(skuInfoVo);
// listIds.add(listId);
}
}
if (CollectionUtil.isEmpty(skuInfoVos)) {
return null;
} else {
// 计算总概率 和 剩余没填概率的平均概率
int size = 0;
BigDecimal sumHitRatio = BigDecimal.ZERO;
for (GoblinGoodsSkuInfoVo skuInfoVo : skuInfoVos) {
if (null == skuInfoVo.getHitRatio()) {
size++;
} else {
sumHitRatio = sumHitRatio.add(skuInfoVo.getHitRatio());
}
}
/**
* 剔除掉没库存的商品再去算未设置概率商品的平均概率 会导致未设置概率的商品的概率增加
* 如果不剔除掉没库存的商品去算未设置概率商品的平均概率 会导致总概率小于100 如果随机数还是0-100的话就有可能会中奖溢出
* 想保持概率 1.不剔除无库存商品算平均概率 2.随机数最大值为排序后概率的最后一个值
*/
BigDecimal avgHitRatio = BigDecimal.ZERO;
if (size > 0) {// 说明有未设置抽奖概率的
avgHitRatio = new BigDecimal(100).subtract(sumHitRatio).divide(new BigDecimal(size), 2, RoundingMode.HALF_UP);
}
// 未设置概率的写入概率
ArrayList<GoblinGoodsSkuInfoVo> newSkuInfoVos = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
// ArrayList<String> newListIds = ObjectUtil.cloneArrayListString();
int skuListSize = skuInfoVos.size();
for (int i = 0; i < skuListSize; i++) {
GoblinGoodsSkuInfoVo infoVo = skuInfoVos.get(i);
if (null == infoVo.getHitRatio() || infoVo.getHitRatio().compareTo(BigDecimal.ZERO) < 0) {
/**
* 算所得平均概率是0 即中不了 剔除掉
* 但是这么处理会导致前端页面显示有库存 买的时候显示没有
* 所以要么概率加起来必须100 要么前端计算盲盒总概率的时候也要同样处理
*/
if (avgHitRatio.compareTo(BigDecimal.ZERO) <= 0) {
continue;
} else {
infoVo.setHitRatio(avgHitRatio);
}
}
// 等于0的最终概率就是设置的值 大于0最终的概率是自己的+上面的
if (i > 0) {
infoVo.setHitRatio(skuInfoVos.get(i - 1).getHitRatio().add(infoVo.getHitRatio()));
}
newSkuInfoVos.add(infoVo);
// newListIds.add(listIds.get(i));
}
if (CollectionUtil.isEmpty(newSkuInfoVos)) {
log.info("该盲盒概率超过100导致不能卖 skuIdList:{}", skuIdList);
return null;
}
// 按照概率排序 按照上面的运算最后一定是最大的不用排序了
// List<GoblinGoodsSkuInfoVo> listSort = newSkuInfoVos.stream().sorted(Comparator.comparing(GoblinGoodsSkuInfoVo::getHitRatio)).collect(Collectors.toList());
List<BigDecimal> hitRatioList = newSkuInfoVos.stream().map(GoblinGoodsSkuInfoVo::getHitRatio).collect(Collectors.toList());
// 根据区块值来获取抽取到的物品索引
double nextDouble = Math.random();
BigDecimal nextDoubleNew = BigDecimal.valueOf(nextDouble);
nextDoubleNew = nextDoubleNew.multiply(hitRatioList.get(hitRatioList.size() - 1)).setScale(4, RoundingMode.HALF_UP);
hitRatioList.add(nextDoubleNew);
Collections.sort(hitRatioList);
int index = hitRatioList.indexOf(nextDoubleNew);
GoblinGoodsSkuInfoVo goodsSkuInfoVo = newSkuInfoVos.get(index);
// String endListId = newListIds.get(index);
// 判断库存
int surplusGeneral = goblinRedisUtils.decrSkuStock(listId, goodsSkuInfoVo.getSkuId(), number);
if (surplusGeneral < 0) {
goblinRedisUtils.incrSkuStock(listId, goodsSkuInfoVo.getSkuId(), number);
return lotteryDraw(skuIdList, number, nowTime, listId);
} else {
// HashMap<String, Object> map = CollectionUtil.mapStringObject();
// map.put("goodsSkuInfoVo", goodsSkuInfoVo);
// map.put("listId", endListId);
// return map;
return goodsSkuInfoVo;
}
}
} catch (Exception e) {
log.error("NFT下单-抽盲盒异常", e);
return null;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment