创建订单扣除库存

This commit is contained in:
2024-07-03 10:12:06 +08:00
parent dfdeca9612
commit 09bfa5bdec
6 changed files with 129 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ import com.chaozhanggui.system.cashierservice.entity.TbProductWithBLOBs;
import com.chaozhanggui.system.cashierservice.entity.vo.ShopGroupInfoVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Component;
import java.util.List;
@@ -36,4 +37,7 @@ public interface TbProductMapper {
void upGroupRealSalesNumber(@Param("id") String id,@Param("number") Integer number);
void updateStockById(@Param("productId") String productId, @Param("num") Integer num);
@Update("update tb_product set stock_number=stock_number-#{num} WHERE id=#{id} and stock_number-#{num} > 0")
int decrStock(@Param("id") String id, @Param("num") Integer num);
}

View File

@@ -5,6 +5,7 @@ import com.chaozhanggui.system.cashierservice.entity.TbProductSkuWithBLOBs;
import com.chaozhanggui.system.cashierservice.entity.vo.HomeVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Component;
import java.util.List;
@@ -39,4 +40,7 @@ public interface TbProductSkuMapper {
List<TbProductSku> selectSkus(@Param("list") List<String> productId);
List<TbProductSku> selectSku(@Param("productId") String productId);
}
@Update("update tb_product_sku set stock_number=stock_number-#{num} WHERE id=#{id} and stock_number-#{num} > 0")
int decrStock(@Param("id") String id, @Param("num") Integer num);
}

View File

@@ -22,4 +22,6 @@ public class RedisCst {
public static final String COUPONS_COIN_KEY = "COUPONS:COIN:KEY";
public static final String OUT_NUMBER="ORDER:NUMBER:";
// 创建订单锁
public static final String CREATE_ORDER_LOCK = "CREATE_ORDER_LOCK:";
}

View File

@@ -12,12 +12,14 @@ import com.chaozhanggui.system.cashierservice.redis.RedisCst;
import com.chaozhanggui.system.cashierservice.redis.RedisUtil;
import com.chaozhanggui.system.cashierservice.util.DateUtils;
import com.chaozhanggui.system.cashierservice.util.JSONUtil;
import com.chaozhanggui.system.cashierservice.util.LockUtils;
import com.chaozhanggui.system.cashierservice.util.N;
import com.chaozhanggui.system.cashierservice.wxUtil.WechatUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
@@ -68,10 +70,20 @@ public class CartService {
@Autowired
private TbShopInfoMapper tbShopInfoMapper;
public CartService(TbUserShopMsgMapper tbUserShopMsgMapper, WechatUtil wechatUtil, TbShopOpenIdMapper shopOpenIdMapper) {
private final ProductService productService;
private final TbProductMapper tbProductMapper;
private final RedisTemplate<String, Object> redisTemplate;
public CartService(TbUserShopMsgMapper tbUserShopMsgMapper, WechatUtil wechatUtil, TbShopOpenIdMapper shopOpenIdMapper, ProductService productService, TbProductMapper tbProductMapper, RedisTemplate<String, Object> redisTemplate) {
this.tbUserShopMsgMapper = tbUserShopMsgMapper;
this.wechatUtil = wechatUtil;
this.shopOpenIdMapper = shopOpenIdMapper;
this.productService = productService;
this.tbProductMapper = tbProductMapper;
this.redisTemplate = redisTemplate;
}
public void initCart(JSONObject jsonObject) {
@@ -110,6 +122,7 @@ public class CartService {
/**
* 加入购物车
*
* @param jsonObject 商品信息
*/
// @Transactional(rollbackFor = Exception.class)
@@ -276,14 +289,16 @@ public class CartService {
// log.error("长链接错误 createCart{}", e.getMessage());
// }
// }
public void createCart(JSONObject jsonObject) {
try {
String tableId = jsonObject.getString("tableId");
String shopId = jsonObject.getString("shopId");
String productId = jsonObject.getString("productId");
String key = tableId + "-" + shopId;
TbProduct tbProduct = productMapper.selectById(Integer.valueOf(productId));
TbProductSkuWithBLOBs tbProductSkuWithBLOBs = null;
if (tbProduct == null) {
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("status", "fail");
@@ -307,8 +322,8 @@ public class CartService {
throw new MsgException("该商品已售罄");
}
} else {
TbProductSkuWithBLOBs tbProductSkuWithBLOBs = productSkuMapper.selectByPrimaryKey(Integer.valueOf(skuId));
if(tbProductSkuWithBLOBs.getIsPauseSale().equals(1)){//是否售罄
tbProductSkuWithBLOBs = productSkuMapper.selectByPrimaryKey(Integer.valueOf(skuId));
if (tbProductSkuWithBLOBs.getIsPauseSale().equals(1)) {//是否售罄
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("status", "fail");
jsonObject1.put("msg", "该商品已售罄");
@@ -325,10 +340,13 @@ public class CartService {
if (redisUtil.exists(RedisCst.TABLE_CART.concat(jsonObject.getString("tableId").concat("-").concat(shopId)))) {
JSONArray array = JSON.parseArray(redisUtil.getMessage(RedisCst.TABLE_CART.concat(jsonObject.getString("tableId").concat("-").concat(shopId))));
// 未创建购物车,新增购物车
if (Objects.isNull(array) || array.isEmpty()) {
if (buyNum > 0) {
TbCashierCart cashierCart = addCart(jsonObject.getString("productId"), skuId,
jsonObject.getInteger("userId"), buyNum, tableId, shopId);
jsonArray.add(cashierCart);
amount = amount.add(new BigDecimal(cashierCart.getNumber()).multiply(cashierCart.getSalePrice().add(cashierCart.getPackFee())));
}
@@ -337,10 +355,13 @@ public class CartService {
for (int i = 0; i < array.size(); i++) {
JSONObject object = array.getJSONObject(i);
TbCashierCart cashierCart = JSONUtil.parseJSONStr2T(object.toJSONString(), TbCashierCart.class);
// 已添加购物车商品,加数量
if (cashierCart.getSkuId().equals(skuId)) {
cashierCart.setTotalNumber(cashierCart.getTotalNumber() + buyNum);
cashierCart.setNumber(cashierCart.getNumber() + buyNum);
if (cashierCart.getNumber() > 0) {
cashierCart.setTotalAmount(new BigDecimal(cashierCart.getTotalNumber()).multiply(cashierCart.getSalePrice().add(cashierCart.getPackFee())));
cashierCart.setUpdatedAt(Instant.now().toEpochMilli());
cashierCartMapper.updateByPrimaryKeySelective(cashierCart);
@@ -353,13 +374,16 @@ public class CartService {
jsonArray.add(cashierCart);
amount = amount.add(new BigDecimal(cashierCart.getTotalNumber()).multiply(cashierCart.getSalePrice().add(cashierCart.getPackFee())));
}
// 已有购物车中不存在,新增
if (flag && buyNum > 0) {
TbCashierCart cashierCart = addCart(jsonObject.getString("productId"), skuId,
jsonObject.getInteger("userId"), buyNum, tableId, jsonObject.getString("shopId"));
jsonArray.add(cashierCart);
amount = amount.add(new BigDecimal(cashierCart.getTotalNumber()).multiply(cashierCart.getSalePrice().add(cashierCart.getPackFee())));
}
}
// 未创建购物车新增
} else {
if (buyNum > 0) {
TbCashierCart cashierCart = addCart(jsonObject.getString("productId"), skuId,
@@ -376,6 +400,7 @@ public class CartService {
jsonObject1.put("data", jsonArray);
jsonObject1.put("amount", amount);
PushToAppChannelHandlerAdapter.getInstance().AppSendInfo(jsonObject1.toString(), jsonObject.getString("tableId").concat("-").concat(shopId), "", false);
} catch (Exception e) {
log.error("长链接错误 createCart{}", e.getMessage());
}
@@ -383,9 +408,10 @@ public class CartService {
/**
* 修改库存并根据警告线发送消息
* @param product 商品
*
* @param product 商品
* @param productSku sku
* @param num 库存数
* @param num 库存数
*/
private void updateProductStock(TbProduct product, TbProductSkuWithBLOBs productSku, Integer num) {
String key = RedisCst.PRODUCT + product.getShopId() + ":product" + product.getId();
@@ -411,6 +437,7 @@ public class CartService {
/**
* 校验商品库存警戒线并通知商户
*
* @param productSku sku
*/
private void checkWarnLineAndSendMsg(TbProductSku productSku, TbProduct product, Integer num) {
@@ -438,13 +465,13 @@ public class CartService {
List<TbShopOpenId> shopOpenIds = shopOpenIdMapper.selectByShopId(Integer.valueOf(product.getShopId()));
shopOpenIds.forEach(item -> {
wechatUtil.sendStockWarnMsg(shopInfo.getShopName(), product.getName(),
product.getIsDistribute() == 1 ? String.valueOf(product.getStockNumber()-num) : String.valueOf(productSku.getStockNumber() - num),
product.getIsDistribute() == 1 ? String.valueOf(product.getStockNumber() - num) : String.valueOf(productSku.getStockNumber() - num),
"耗材库存不足,请及时补充。", item.getOpenId());
});
}
}
private TbCashierCart addCart(String productId, String skuId, Integer userId, Integer num, String tableId, String shopId) throws Exception {
private TbCashierCart addCart(String productId, String skuId, Integer userId, Integer num, String tableId, String shopId) throws RuntimeException {
try {
TbProduct product = productMapper.selectById(Integer.valueOf(productId));
String key = tableId + "-" + shopId;
@@ -536,6 +563,11 @@ public class CartService {
JSONObject object = array.getJSONObject(i);
TbCashierCart cashierCart = JSONUtil.parseJSONStr2T(object.toJSONString(), TbCashierCart.class);
TbProductSkuWithBLOBs tbProduct = productSkuMapper.selectByPrimaryKey(Integer.valueOf(cashierCart.getSkuId()));
TbProduct tbProduct1 = tbProductMapper.selectById(Integer.valueOf(tbProduct.getProductId()));
log.info("开始修改库存商品id{},商品名:{}", tbProduct1.getId(), tbProduct1.getName());
// 修改库存
productService.updateStock(tbProduct.getProductId(), tbProduct.getId(), cashierCart.getNumber(), tbProduct1.getIsDistribute() == 1);
totalAmount = totalAmount.add(cashierCart.getTotalAmount());
packAMount = packAMount.add(cashierCart.getPackFee());
originAmount = originAmount.add(cashierCart.getTotalAmount());
@@ -709,11 +741,7 @@ public class CartService {
orderInfoMapper.insert(orderInfo);
orderId = orderInfo.getId();
// 发送mq消息
JSONObject jsonObject2=new JSONObject();
jsonObject2.put("orderId",orderInfo.getId());
jsonObject2.put("type","create");
producer.cons(jsonObject2.toString());
}
for (TbOrderDetail orderDetail : orderDetails) {
orderDetail.setOrderId(orderId);
@@ -728,6 +756,14 @@ public class CartService {
cashierCartMapper.updateByPrimaryKeySelective(cashierCart);
object.put("updatedAt", System.currentTimeMillis());
object.put("orderId", orderId + "");
// 发送mq消息
JSONObject jsonObject2 = new JSONObject();
jsonObject2.put("orderId", orderInfo.getId());
jsonObject2.put("type", "create");
jsonObject2.put("cartId", cashierCart.getId());
log.info("开始发送mq消息消耗库存消息内容{}", jsonObject2);
producer.cons(jsonObject2.toString());
}
redisUtil.saveMessage(RedisCst.TABLE_CART.concat(jsonObject.getString("tableId")).concat("-").concat(shopId), array.toJSONString());
orderInfo.setDetailList(orderDetails);
@@ -747,6 +783,8 @@ public class CartService {
jsonObject12.put("data", new JSONArray());
PushToAppChannelHandlerAdapter.getInstance().AppSendInfo(jsonObject12.toString(), jsonObject.getString("tableId").concat("-").concat(shopId), "", false);
redisUtil.saveMessage(RedisCst.ORDER_EXPIRED.concat(orderId.toString()), orderId.toString(), 60 * 16L);
} catch (Exception e) {
log.info("长链接错误 addCart{}", e.getMessage());
e.printStackTrace();

View File

@@ -8,6 +8,7 @@ import com.chaozhanggui.system.cashierservice.dao.*;
import com.chaozhanggui.system.cashierservice.entity.*;
import com.chaozhanggui.system.cashierservice.entity.dto.HomeDto;
import com.chaozhanggui.system.cashierservice.entity.vo.*;
import com.chaozhanggui.system.cashierservice.exception.MsgException;
import com.chaozhanggui.system.cashierservice.sign.CodeEnum;
import com.chaozhanggui.system.cashierservice.sign.Result;
import com.chaozhanggui.system.cashierservice.util.*;
@@ -433,4 +434,35 @@ public class ProductService {
}
return Result.success(CodeEnum.SUCCESS, confirmVo);
}
/**
* 库存修改
*
* @param tbProduct 商品
* @param tbProductSkuWithBLOBs sku
* @param buyNum 购买数量
*/
public void updateStock(TbProduct tbProduct, TbProductSkuWithBLOBs tbProductSkuWithBLOBs, Integer buyNum) {
if (tbProduct.getIsDistribute() == 1) {
if (tbProductMapper.decrStock(String.valueOf(tbProduct.getId()), buyNum) < 1) {
throw new MsgException("库存修改失败,请稍后再试");
}
}else {
if (tbProductSkuMapper.decrStock(String.valueOf(tbProductSkuWithBLOBs.getId()), buyNum) < 1) {
throw new MsgException("库存修改失败,请稍后再试");
}
}
}
public void updateStock(String id, Integer skuId, Integer buyNum, boolean isDistribute) {
if (isDistribute) {
if (tbProductMapper.decrStock(String.valueOf(id), buyNum) < 1) {
throw new MsgException("库存不足,下单失败");
}
}else {
if (tbProductSkuMapper.decrStock(String.valueOf(skuId), buyNum) < 1) {
throw new MsgException("库存不足,下单失败");
}
}
}
}

View File

@@ -0,0 +1,35 @@
package com.chaozhanggui.system.cashierservice.util;
import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
@Slf4j
public class LockUtils {
public static<T> T runFunAndCheckKey(Supplier<T> supplier, RedisTemplate<String, Object> redisTemplate, String lockKey) {
try{
// 创建线程id, 用作判断
String clientId = UUID.randomUUID().toString();
// 设置分布式锁
boolean lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS));
int count = 0;
while (!lock) {
if (count++ > 100) {
throw new RuntimeException("系统繁忙, 稍后再试");
}
Thread.sleep(20);
lock = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS));
}
return supplier.get();
} catch (Exception e){
log.info("执行出错:{}", e.getMessage());
throw new RuntimeException(e.getMessage());
}finally{
redisTemplate.delete(lockKey);
}
}
}