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

Commit 2f76fe8f authored by jiangxiulong's avatar jiangxiulong

盲盒抽藏品

parent 15c92a05
...@@ -34,6 +34,9 @@ public class GoblinNftOrderVo implements Serializable, Cloneable { ...@@ -34,6 +34,9 @@ public class GoblinNftOrderVo implements Serializable, Cloneable {
@ApiModelProperty(value = "款式id") @ApiModelProperty(value = "款式id")
private String skuId; private String skuId;
@ApiModelProperty(value = "盲盒抽取的款式id")
private String boxSkuId;
@ApiModelProperty(value = "数量") @ApiModelProperty(value = "数量")
private Integer num; private Integer num;
...@@ -135,6 +138,7 @@ public class GoblinNftOrderVo implements Serializable, Cloneable { ...@@ -135,6 +138,7 @@ public class GoblinNftOrderVo implements Serializable, Cloneable {
this.setOrderId(source.getOrderId()); this.setOrderId(source.getOrderId());
this.setSpuId(source.getSpuId()); this.setSpuId(source.getSpuId());
this.setSkuId(source.getSkuId()); this.setSkuId(source.getSkuId());
this.setBoxSkuId(source.getBoxSkuId());
this.setNum(source.getNum()); this.setNum(source.getNum());
this.setStoreId(source.getStoreId()); this.setStoreId(source.getStoreId());
this.setStoreName(source.getStoreName()); this.setStoreName(source.getStoreName());
......
...@@ -40,6 +40,11 @@ public class GoblinNftOrder implements Serializable, Cloneable { ...@@ -40,6 +40,11 @@ public class GoblinNftOrder implements Serializable, Cloneable {
*/ */
private String skuId; private String skuId;
/**
* 盲盒抽取的款式id
*/
private String boxSkuId;
/** /**
* 数量 * 数量
*/ */
......
...@@ -171,7 +171,11 @@ public abstract class AbstractOrderCloseReceiver implements StreamListener<Strin ...@@ -171,7 +171,11 @@ public abstract class AbstractOrderCloseReceiver implements StreamListener<Strin
GoblinNftOrderVo nftOrder = goblinNftUtils.getNftOrder(orderId); GoblinNftOrderVo nftOrder = goblinNftUtils.getNftOrder(orderId);
if (nftOrder.getStatus().equals(GoblinStatusConst.NftStatus.ORDER_STATUS_1.getValue())) { if (nftOrder.getStatus().equals(GoblinStatusConst.NftStatus.ORDER_STATUS_1.getValue())) {
// 库存购买数量回滚 // 库存购买数量回滚
goblinNftUtils.backSkuCountAndStock(nftOrder.getUserId(), nftOrder.getSkuId(), nftOrder.getNum()); if (StringUtils.isEmpty(nftOrder.getBoxSkuId())) {
goblinNftUtils.backSkuCountAndStock(nftOrder.getUserId(), nftOrder.getSkuId(), nftOrder.getNum());
} else {
goblinNftUtils.decrSkuStock(nftOrder.getBoxSkuId(), nftOrder.getNum());
}
// 订单状态 // 订单状态
nftOrder.setStatus(GoblinStatusConst.NftStatus.ORDER_STATUS_3.getValue()); nftOrder.setStatus(GoblinStatusConst.NftStatus.ORDER_STATUS_3.getValue());
......
...@@ -138,6 +138,7 @@ CREATE TABLE goblin_nft_order ...@@ -138,6 +138,7 @@ CREATE TABLE goblin_nft_order
order_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '订单id', order_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '订单id',
spu_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '商品id', spu_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '商品id',
sku_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '款式id', sku_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '款式id',
box_sku_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '盲盒抽取的款式id',
num INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '数量', num INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '数量',
store_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '店铺id', store_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '店铺id',
store_name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '商铺名称', store_name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '商铺名称',
......
...@@ -23,11 +23,11 @@ import org.springframework.stereotype.Service; ...@@ -23,11 +23,11 @@ import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.LinkedList; import java.util.*;
import java.util.Map; import java.util.stream.Collectors;
import java.util.Objects;
import static com.liquidnet.commons.lang.util.DateUtil.DTF_YMD_HMS; import static com.liquidnet.commons.lang.util.DateUtil.DTF_YMD_HMS;
...@@ -103,21 +103,35 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService { ...@@ -103,21 +103,35 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService {
if (!StringUtils.isEmpty(platVoucherCode) && !StringUtils.isEmpty(storeVoucherCode)) { if (!StringUtils.isEmpty(platVoucherCode) && !StringUtils.isEmpty(storeVoucherCode)) {
return ResponseDto.failure("平台券与店铺券不可一起使用哦~"); return ResponseDto.failure("平台券与店铺券不可一起使用哦~");
}*/ }*/
String boxSkuId = "";
// 判断数量限购 if (skuVo.getUnbox().equals("1")) {// 盲盒逻辑
int limitCount = skuVo.getBuyLimit(); GoblinGoodsInfoVo spuInfoVo = goblinRedisUtils.getGoodsInfoVo(spuId);
if (!Objects.equals(0, limitCount)) { List<String> skuIdList = spuInfoVo.getSkuIdList();
String isOutLimit = goblinOrderUtils.judgeOrderLimit(uid, skuId, number, limitCount); if (CollectionUtil.isEmpty(skuIdList)) {
if (!StringUtils.isEmpty(isOutLimit)) { return ResponseDto.failure("该商品SPU不存在~");
goblinRedisUtils.decrSkuCountByUid(uid, skuId, number); } else {
return ResponseDto.failure("您已超出限购数量~"); GoblinGoodsSkuInfoVo skuInfoVo = lotteryDraw(skuIdList, number);
if (null == skuInfoVo) {
return ResponseDto.failure("盲盒库存不足啦~");
}
boxSkuId = skuInfoVo.getSkuId();
}
} else {// 普通藏品逻辑
// 判断数量限购
int limitCount = skuVo.getBuyLimit();
if (!Objects.equals(0, limitCount)) {
String isOutLimit = goblinOrderUtils.judgeOrderLimit(uid, skuId, number, limitCount);
if (!StringUtils.isEmpty(isOutLimit)) {
goblinRedisUtils.decrSkuCountByUid(uid, skuId, number);
return ResponseDto.failure("您已超出限购数量~");
}
}
// 判断库存
int surplusGeneral = nftOrderUtils.decrSkuStock(skuId, number);
if (surplusGeneral < 0) {
nftOrderUtils.backSkuCountAndStock(uid, skuId, number);
return ResponseDto.failure("库存不足啦~");
} }
}
// 判断库存
int surplusGeneral = nftOrderUtils.decrSkuStock(skuId, number);
if (surplusGeneral < 0) {
nftOrderUtils.backSkuCountAndStock(uid, skuId, number);
return ResponseDto.failure("库存不足啦~");
} }
/** /**
...@@ -153,7 +167,7 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService { ...@@ -153,7 +167,7 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService {
}*/ }*/
// 下单数据 // 下单数据
GoblinNftOrder nftOrder = order(payParam, skuVo.getStoreId(), uid, spuId, number, orderId, orderCode, totalPrice, voucherPrice, storeVoucherPrice); GoblinNftOrder nftOrder = order(payParam, skuVo.getStoreId(), uid, spuId, number, orderId, orderCode, totalPrice, voucherPrice, storeVoucherPrice, boxSkuId);
if (null == nftOrder) { if (null == nftOrder) {
nftOrderUtils.backSkuCountAndStock(uid, skuId, number); nftOrderUtils.backSkuCountAndStock(uid, skuId, number);
return ResponseDto.failure("下单失败~"); return ResponseDto.failure("下单失败~");
...@@ -176,10 +190,71 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService { ...@@ -176,10 +190,71 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService {
} }
} }
private GoblinGoodsSkuInfoVo lotteryDraw(List<String> skuIdList, int number) {
try {
ArrayList<GoblinGoodsSkuInfoVo> skuInfoVos = ObjectUtil.cloneArrayGoblinGoodsSkuInfoListVo();
for (String kid : skuIdList) {
GoblinGoodsSkuInfoVo skuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(kid);
int skuStock = goblinRedisUtils.getSkuStock(kid);
if (null != skuInfoVo && skuStock > 0) {// 有库存的加入奖池
skuInfoVos.add(skuInfoVo);
}
}
if (CollectionUtil.isEmpty(skuInfoVos)) {
return null;
} else {
// 计算总概率 和 剩余没填概率的平均概率
BigDecimal sumHitRatio = skuInfoVos.stream().map(GoblinGoodsSkuInfoVo::getHitRatio).reduce(BigDecimal.ZERO, BigDecimal::add);
int size = skuInfoVos.size();
/**
* 剔除掉没库存的商品再去算未设置概率商品的平均概率 会导致未设置概率的商品的概率增加
* 如果不剔除掉没库存的商品去算未设置概率商品的平均概率 会导致总概率小于100 如果随机数还是0-100的话就有可能会中奖溢出
* 想保持概率 1.不剔除无库存商品算平均概率 2.随机数最大值为排序后概率的最后一个值
*/
// ************
BigDecimal avgHitRatio = new BigDecimal(100).subtract(sumHitRatio).divide(new BigDecimal(size), 2, RoundingMode.HALF_UP);
// 未设置概率的写入概率
for (int i = 0; i < size; i++) {
GoblinGoodsSkuInfoVo infoVo = skuInfoVos.get(i);
if (null == infoVo.getHitRatio() || infoVo.getHitRatio().compareTo(BigDecimal.ZERO) <= 0) {
skuInfoVos.get(i).setHitRatio(avgHitRatio);
}
// 等于0的最终概率就是设置的值 大于0最终的概率是自己的+上面的
if (i > 0) {
skuInfoVos.get(i).setHitRatio(skuInfoVos.get(i - 1).getHitRatio().add(skuInfoVos.get(i).getHitRatio()));
}
}
// 按照概率排序
List<GoblinGoodsSkuInfoVo> listSort = skuInfoVos.stream().sorted(Comparator.comparing(GoblinGoodsSkuInfoVo::getHitRatio)).collect(Collectors.toList());
List<BigDecimal> hitRatioList = listSort.stream().map(GoblinGoodsSkuInfoVo::getHitRatio).collect(Collectors.toList());
// 根据区块值来获取抽取到的物品索引
double nextDouble = Math.random();
BigDecimal nextDoubleNew = BigDecimal.valueOf(nextDouble);
hitRatioList.add(nextDoubleNew);
Collections.sort(hitRatioList);
int index = hitRatioList.indexOf(nextDoubleNew);
GoblinGoodsSkuInfoVo goodsSkuInfoVo = listSort.get(index);
// 判断库存
int surplusGeneral = nftOrderUtils.decrSkuStock(goodsSkuInfoVo.getSkuId(), number);
if (surplusGeneral < 0) {
nftOrderUtils.incrSkuStock(goodsSkuInfoVo.getSkuId(), number);
return lotteryDraw(skuIdList, number);
} else {
return goodsSkuInfoVo;
}
}
} catch (Exception e) {
log.error("NFT下单-抽盲盒异常 e:{}", e);
return null;
}
}
private GoblinNftOrder order( private GoblinNftOrder order(
GoblinNftOrderPayParam payParam, String storeId, String uid, String spuId, int number, GoblinNftOrderPayParam payParam, String storeId, String uid, String spuId, int number,
String orderId, String orderCode, String orderId, String orderCode,
BigDecimal totalPrice, BigDecimal voucherPrice, BigDecimal storeVoucherPrice BigDecimal totalPrice, BigDecimal voucherPrice, BigDecimal storeVoucherPrice, String boxSkuId
) { ) {
try { try {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
...@@ -197,6 +272,7 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService { ...@@ -197,6 +272,7 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService {
nftOrder.setOrderId(orderId); nftOrder.setOrderId(orderId);
nftOrder.setSpuId(spuId); nftOrder.setSpuId(spuId);
nftOrder.setSkuId(payParam.getSkuId()); nftOrder.setSkuId(payParam.getSkuId());
nftOrder.setBoxSkuId(boxSkuId);
nftOrder.setNum(number); nftOrder.setNum(number);
nftOrder.setStoreId(storeId); nftOrder.setStoreId(storeId);
nftOrder.setStoreName(storeName); nftOrder.setStoreName(storeName);
...@@ -295,7 +371,7 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService { ...@@ -295,7 +371,7 @@ public class GoblinNftOrderServiceImpl implements IGoblinNftOrderService {
nftOrder.setPayCode(payCode); nftOrder.setPayCode(payCode);
sqlDataOrder.add(new Object[]{ sqlDataOrder.add(new Object[]{
nftOrder.getOrderId(), nftOrder.getSpuId(), nftOrder.getSkuId(), nftOrder.getOrderId(), nftOrder.getSpuId(), nftOrder.getSkuId(), nftOrder.getBoxSkuId(),
nftOrder.getNum(), nftOrder.getStoreId(), nftOrder.getStoreName(), nftOrder.getOrderCode(), nftOrder.getUserId(), nftOrder.getUserName(), nftOrder.getUserMobile(), nftOrder.getPriceTotal(), nftOrder.getPriceCoupon(), nftOrder.getNum(), nftOrder.getStoreId(), nftOrder.getStoreName(), nftOrder.getOrderCode(), nftOrder.getUserId(), nftOrder.getUserName(), nftOrder.getUserMobile(), nftOrder.getPriceTotal(), nftOrder.getPriceCoupon(),
nftOrder.getStorePriceCoupon(), nftOrder.getPriceRedEnvelope(), nftOrder.getPriceVoucher(), nftOrder.getPriceActual(), nftOrder.getUcouponId(), nftOrder.getStoreCouponId(), nftOrder.getRedEnvelopeCode(), nftOrder.getStatus(), nftOrder.getSource(), nftOrder.getStorePriceCoupon(), nftOrder.getPriceRedEnvelope(), nftOrder.getPriceVoucher(), nftOrder.getPriceActual(), nftOrder.getUcouponId(), nftOrder.getStoreCouponId(), nftOrder.getRedEnvelopeCode(), nftOrder.getStatus(), nftOrder.getSource(),
nftOrder.getOrderType(), nftOrder.getPayType(), nftOrder.getDeviceFrom(), nftOrder.getVersion(), nftOrder.getPayCountdownMinute(), nftOrder.getIpAddress(), nftOrder.getCreatedAt(), nftOrder.getPayCode() nftOrder.getOrderType(), nftOrder.getPayType(), nftOrder.getDeviceFrom(), nftOrder.getVersion(), nftOrder.getPayCountdownMinute(), nftOrder.getIpAddress(), nftOrder.getCreatedAt(), nftOrder.getPayCode()
......
...@@ -53,6 +53,16 @@ public class GoblinRedisUtils { ...@@ -53,6 +53,16 @@ public class GoblinRedisUtils {
return (int) redisUtil.decr(rk, stock); return (int) redisUtil.decr(rk, stock);
} }
public int getSkuStock(String skuId) {
String rk = GoblinRedisConst.REAL_STOCK_SKU.concat(skuId);
Object obj = redisUtil.get(rk);
if (obj == null) {
return 0;
} else {
return (int) obj;
}
}
public GoblinStoreInfoVo getStoreInfoVo(String storeId) { public GoblinStoreInfoVo getStoreInfoVo(String storeId) {
String rk = GoblinRedisConst.BASIC_STORE.concat(storeId); String rk = GoblinRedisConst.BASIC_STORE.concat(storeId);
GoblinStoreInfoVo vo = (GoblinStoreInfoVo) redisUtil.get(rk); GoblinStoreInfoVo vo = (GoblinStoreInfoVo) redisUtil.get(rk);
......
...@@ -37,6 +37,7 @@ public class ObjectUtil { ...@@ -37,6 +37,7 @@ public class ObjectUtil {
private static final ArrayList<AdamEntersVo> arrayListObject = new ArrayList<>(); private static final ArrayList<AdamEntersVo> arrayListObject = new ArrayList<>();
private static final ArrayList<String> arrayListString = new ArrayList<>(); private static final ArrayList<String> arrayListString = new ArrayList<>();
private static final ArrayList<KylinOrderListVo> arrayKylinOrderListVo = new ArrayList<>(); private static final ArrayList<KylinOrderListVo> arrayKylinOrderListVo = new ArrayList<>();
private static final ArrayList<KylinOrderListVo> arrayGoblinGoodsSkuInfoListVo = new ArrayList<>();
private static final LinkedMultiValueMap<String, String> linkedMultiValueMapStringAndString = new LinkedMultiValueMap<String, String>(); private static final LinkedMultiValueMap<String, String> linkedMultiValueMapStringAndString = new LinkedMultiValueMap<String, String>();
private static final BasicDBObject basicDBObject = new BasicDBObject(); private static final BasicDBObject basicDBObject = new BasicDBObject();
private static final ArrayList<KylinOrderCoupons> kylinOrderCouponsArrayList = new ArrayList<>(); private static final ArrayList<KylinOrderCoupons> kylinOrderCouponsArrayList = new ArrayList<>();
...@@ -111,6 +112,10 @@ public class ObjectUtil { ...@@ -111,6 +112,10 @@ public class ObjectUtil {
return (ArrayList<KylinOrderListVo>) arrayKylinOrderListVo.clone(); return (ArrayList<KylinOrderListVo>) arrayKylinOrderListVo.clone();
} }
public static ArrayList<GoblinGoodsSkuInfoVo> cloneArrayGoblinGoodsSkuInfoListVo() {
return (ArrayList<GoblinGoodsSkuInfoVo>) arrayGoblinGoodsSkuInfoListVo.clone();
}
public static ArrayList<String> cloneArrayListString() { public static ArrayList<String> cloneArrayListString() {
return (ArrayList<String>) arrayListString.clone(); return (ArrayList<String>) arrayListString.clone();
} }
......
...@@ -47,7 +47,7 @@ goblin_order.store.refundLog=INSERT INTO goblin_back_order_log (`back_order_log_ ...@@ -47,7 +47,7 @@ goblin_order.store.refundLog=INSERT INTO goblin_back_order_log (`back_order_log_
goblin_order.store.backOrder=INSERT INTO goblin_back_order (`back_order_id`,`back_code`,`order_id`,`order_code`,`store_id`,`user_id`,`sku_id_nums`,`type`,`reason`,`describes`,`real_back_price`,`status`,`created_at`,`audit_at`,`error_reason`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) goblin_order.store.backOrder=INSERT INTO goblin_back_order (`back_order_id`,`back_code`,`order_id`,`order_code`,`store_id`,`user_id`,`sku_id_nums`,`type`,`reason`,`describes`,`real_back_price`,`status`,`created_at`,`audit_at`,`error_reason`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
#-------- NFT ------- #-------- NFT -------
goblin_nft_order.insert=INSERT INTO goblin_nft_order (`order_id`,`spu_id`,`sku_id`,`num`,`store_id`,`store_name`,`order_code`,`user_id`,`user_name`,`user_mobile`,`price_total`,`price_coupon`,`store_price_coupon`,`price_red_envelope`,`price_voucher`,`price_actual`,`ucoupon_id`,`store_coupon_id`,`red_envelope_code`,`status`,`source`,`order_type`,`pay_type`,`device_from`,`version`,`pay_countdown_minute`,`ip_address`,`created_at`,`pay_code`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) goblin_nft_order.insert=INSERT INTO goblin_nft_order (`order_id`,`spu_id`,`sku_id`,`box_sku_id`,`num`,`store_id`,`store_name`,`order_code`,`user_id`,`user_name`,`user_mobile`,`price_total`,`price_coupon`,`store_price_coupon`,`price_red_envelope`,`price_voucher`,`price_actual`,`ucoupon_id`,`store_coupon_id`,`red_envelope_code`,`status`,`source`,`order_type`,`pay_type`,`device_from`,`version`,`pay_countdown_minute`,`ip_address`,`created_at`,`pay_code`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
goblin_nft_order.update.pay=UPDATE goblin_nft_order SET payment_type = ?, payment_id=?, pay_code = ?, pay_time = ?, status = ?, updated_at = ? WHERE order_id = ? and (updated_at <= ? or created_at = ? or updated_at is null) goblin_nft_order.update.pay=UPDATE goblin_nft_order SET payment_type = ?, payment_id=?, pay_code = ?, pay_time = ?, status = ?, updated_at = ? WHERE order_id = ? and (updated_at <= ? or created_at = ? or updated_at is null)
goblin_nft_order.update.refund=UPDATE goblin_nft_order SET status = ?, updated_at = ? WHERE order_id = ? and (updated_at <= ? or created_at = ? or updated_at is null) goblin_nft_order.update.refund=UPDATE goblin_nft_order SET status = ?, updated_at = ? WHERE order_id = ? and (updated_at <= ? or created_at = ? or updated_at is null)
goblin_nft_order_refund.insert=INSERT INTO goblin_nft_order_refund (`order_refund_id`,`refund_code`,`order_id`,`order_code`,`store_id`,`user_id`,`price`,`status`,`error_reason`) VALUES (?,?,?,?,?,?,?,?,?) goblin_nft_order_refund.insert=INSERT INTO goblin_nft_order_refund (`order_refund_id`,`refund_code`,`order_id`,`order_code`,`store_id`,`user_id`,`price`,`status`,`error_reason`) VALUES (?,?,?,?,?,?,?,?,?)
......
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