双向同步库存计算

This commit is contained in:
liyj 2025-08-26 18:30:26 +08:00
parent 3d8999d51e
commit 19d97f6829
3 changed files with 56 additions and 9 deletions

View File

@ -5497,7 +5497,10 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
// 1. 批量新增
if (CollUtil.isNotEmpty(newProducts)) {
// 4. 批量生成新商品的ID
List<Long> newIds = shopNumberSeqService.batchCreateNextNo("product_id", newProducts.size());
List<Long> newIds=new ArrayList<>();
synchronized (this){
newIds = shopNumberSeqService.batchCreateNextNo("product_id", newProducts.size());
}
if (newIds == null || newIds.size() != newProducts.size()) {
return Pair.of(false, "生成商品编号异常");
}
@ -5565,6 +5568,7 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
//计算规格
if (existingProducts.get(productId) != null) {
udpateShopProductItemList.get(i).get(0).setItem_id(existingProducts.get(productId));
udpateShopProductItemList.get(i).get(0).setItem_src_id(String.valueOf(existingProducts.get(productId)));
udpateItemIds.add(existingProducts.get(productId));
}
// 处理商品项
@ -5916,12 +5920,16 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl<ShopProductBaseM
List<ShopProductInfo> newShopProductInfoList) {
List<Serializable> itemIds = new ArrayList<>();
if (CollUtil.isEmpty(items)) return itemIds;
List<Long> generatedIds = shopNumberSeqService.batchCreateNextNo("item_id", items.size());
List<Long> generatedIds =new ArrayList<>();
synchronized (this){
generatedIds = shopNumberSeqService.batchCreateNextNo("item_id", items.size());
}
// Map<String,String> cacheMap=new HashMap<>();
for (int i = 0; i < items.size(); i++) {
Long itemId = generatedIds.get(i);
ShopProductItem item = items.get(i);
item.setItem_id(itemId);
item.setItem_src_id(String.valueOf(itemId));
// if(StringUtils.isNotEmpty(item.getItem_spec())){
// String product_uniqid=ShopJsonUtils.generateJsonWithOrgJson(item.getSpec_item_ids(),new Object[]{itemId,item.getItem_unit_price(),"",1002});
// cacheMap.put(item.getProductName(),product_uniqid);

View File

@ -122,7 +122,7 @@ public interface SyncThirdDataService {
*
* @return
*/
Map<String, Integer> getProductStockFromRedis();
Map<String, Double> getProductStockFromRedis();
/**
* 下单或支付后批量累加减商品库存使用 Redis Hash 的原子自增操作保证并发安全

View File

@ -35,7 +35,9 @@ import com.suisung.mall.common.feignService.SearchService;
import com.suisung.mall.common.modules.account.AccountUserBase;
import com.suisung.mall.common.modules.base.ShopBaseProductBrand;
import com.suisung.mall.common.modules.base.ShopBaseProductCategory;
import com.suisung.mall.common.modules.product.ShopProductBase;
import com.suisung.mall.common.modules.product.ShopProductIndex;
import com.suisung.mall.common.modules.product.ShopProductItem;
import com.suisung.mall.common.modules.sixun.SxSyncGoods;
import com.suisung.mall.common.modules.sixun.SxSyncVip;
import com.suisung.mall.common.modules.store.ShopStoreActivityBase;
@ -50,13 +52,11 @@ import com.suisung.mall.common.utils.I18nUtil;
import com.suisung.mall.common.utils.StringUtils;
import com.suisung.mall.shop.base.service.ShopBaseProductBrandService;
import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService;
import com.suisung.mall.shop.base.service.ShopBaseProductSpecService;
import com.suisung.mall.shop.number.service.ShopNumberSeqService;
import com.suisung.mall.shop.page.service.OssService;
import com.suisung.mall.shop.product.service.ShopProductBaseService;
import com.suisung.mall.shop.product.service.ShopProductIndexService;
import com.suisung.mall.shop.product.service.ShopProductItemService;
import com.suisung.mall.shop.product.service.ShopProductSpecItemService;
import com.suisung.mall.shop.sixun.dao.SxDataDao;
import com.suisung.mall.shop.sixun.dto.DataBaseInfo;
import com.suisung.mall.shop.sixun.dto.SxCategoryModel;
@ -788,7 +788,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
// storeDataResultMap = sme.stream().filter(m -> !(m.getValue().equals((double) 0))).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
// }
Map<String, Integer> storeDataResultMap = getProductStockFromRedis();
Map<String, Double> storeDataResultMap = getProductStockFromRedis();
return new ThirdApiRes().success("success", storeDataResultMap);
}
@ -812,7 +812,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
@Override
public Map<String, Integer> getProductStockFromRedis() {
public Map<String, Double> getProductStockFromRedis() {
try {
// Redis 获取 hash 结构的所有键值对
Map<Object, Object> redisHash = redisTemplate.opsForHash().entries(RedisKey.STOREDATARELEASE);
@ -823,7 +823,7 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
return redisHash.entrySet().stream()
.collect(Collectors.toMap(
entry -> String.valueOf(entry.getKey()),
entry -> Convert.toInt(entry.getValue(), 0) // 转换失败时默认为 0
entry -> Convert.toDouble(entry.getValue(), 0.00) // 转换失败时默认为 0
));
} catch (Exception e) {
logger.error("从 Redis 获取商品库存失败: {}", e.getMessage(), e);
@ -845,14 +845,53 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements
continue;
}
try {
QueryWrapper<ShopProductItem> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("item_src_id", productKey);
List<ShopProductItem> shopProductItems=shopProductItemService.list(queryWrapper);
if(shopProductItems==null || shopProductItems.isEmpty()){
continue;
}
ShopProductItem spuItem = shopProductItems.get(0);
cn.hutool.json.JSONArray array_item_spec= JSONUtil.parseArray(spuItem.getItem_spec());
if(array_item_spec.isEmpty()){
continue;
}
cn.hutool.json.JSONObject item = (cn.hutool.json.JSONObject) ((cn.hutool.json.JSONObject) array_item_spec.get(0)).get("item");
String name = Convert.toStr(item.get("name"));
BigDecimal itemQuaryty = getBigDecimal(delta, name);
Long productId = spuItem.getProduct_id();
ShopProductBase productBase = shopProductBaseService.get(productId);
if(productBase==null){
continue;
}
String itemId=productBase.getProduct_number();
// 使用 Redis HINCRBY 保证原子性和高性能
redisTemplate.opsForHash().increment(RedisKey.STOREDATARELEASE, productKey, delta);
redisTemplate.opsForHash().increment(RedisKey.STOREDATARELEASE, itemId, itemQuaryty.doubleValue());
} catch (Exception e) {
logger.error("库存累计失败productKey={}, delta={}, error={}", productKey, delta, e.getMessage(), e);
}
}
}
/**
* 计算最终数量 如果是g转换为kg如果是数量就是直接值
* @param delta
* @param name
* @return
*/
private static BigDecimal getBigDecimal(Integer delta, String name) {
BigDecimal itemQuaryty = new BigDecimal(delta);
if(name.contains("kg")){
String weightStr= name.split("kg")[0];
itemQuaryty=new BigDecimal(weightStr).multiply(new BigDecimal(delta));
}
if(name.contains("g")){
String weightStr= name.split("g")[0];
itemQuaryty=new BigDecimal(weightStr).multiply(new BigDecimal(delta)).divide(new BigDecimal(1000),4,RoundingMode.HALF_UP);
}
return itemQuaryty;
}
/**
* 压缩商家数据并上传cos