数据 同步

This commit is contained in:
2025-04-07 18:08:11 +08:00
parent 1eafd54536
commit bc171691ff
25 changed files with 446 additions and 10 deletions

View File

@@ -38,7 +38,6 @@ public class ProdConsRelationServiceImpl extends ServiceImpl<ProdConsRelationMap
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
Long shopId = StpKit.USER.getShopId(0L);
queryWrapper.eq(ProdConsRelation::getShopId, shopId);
queryWrapper.orderBy(ProdConsRelation::getId, false);
return queryWrapper;
}

View File

@@ -0,0 +1,378 @@
package com.czg.service.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopInfo;
import com.czg.account.entity.SysRole;
import com.czg.account.service.ShopInfoService;
import com.czg.exception.CzgException;
import com.czg.product.entity.*;
import com.czg.product.service.*;
import com.czg.product.vo.ProductGroupVo;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ProdConsRelationMapper;
import com.czg.service.product.mapper.ProdSkuMapper;
import com.czg.utils.AssertUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static com.mybatisflex.core.query.QueryMethods.column;
/**
* @author ww
* @description
*/
@Slf4j
@Service
public class ShopSyncServiceImpl implements ShopSyncService {
@Resource
private ShopInfoService shopInfoService;
@Resource
private ShopProdUnitService unitService;
@Resource
private ShopProdSpecService specService;
@Resource
private ShopProdCategoryService categoryService;
@Resource
private ProductService productService;
@Resource
private ProdSkuService skuService;
@Resource
private ProdGroupService groupService;
@Resource
private ProdGroupRelationService prodGroupRelationService;
@Resource
private ConsInfoService consInfoService;
@Resource
private ConsGroupService consGroupService;
@Resource
private ProdConsRelationService prodConsRelationService;
private void checkShopInfo(Long sourceShopId, Long targetShopId) {
AssertUtil.isNull(sourceShopId, "{}不能为空", "源店铺ID");
AssertUtil.isNull(targetShopId, "{}不能为空", "目标店铺ID");
ShopInfo sourceShop = shopInfoService.getById(sourceShopId);
if (StrUtil.isBlank(sourceShop.getShopType()) || "only".equals(sourceShop.getShopType())
|| sourceShop.getIsHeadShop() == null || sourceShop.getIsHeadShop() != 1) {
throw new CzgException("同步失败,源店铺不是主店铺或源店铺是单店");
}
ShopInfo targetShop = shopInfoService.getById(targetShopId);
if (StrUtil.isBlank(targetShop.getShopType()) || "only".equals(targetShop.getShopType())
|| targetShop.getIsHeadShop() == null || targetShop.getIsHeadShop().equals(1)) {
throw new CzgException("同步失败,目标店铺是主店铺或目标店铺是单店");
}
}
@Override
public void sync(Long sourceShopId, Long targetShopId) {
Map<Long, Long> unitMap;
Map<Long, Long> specMap;
Map<Long, Long> categoryMap;
Map<Long, Long> proMap = new HashMap<>();
Map<Long, Long> skuMap = new HashMap<>();
checkShopInfo(sourceShopId, targetShopId);
//商品
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
CompletableFuture<Map<Long, Long>> futureUnit = CompletableFuture.supplyAsync(() -> syncUnit(sourceShopId, targetShopId), executor);
CompletableFuture<Map<Long, Long>> futureSpec = CompletableFuture.supplyAsync(() -> syncSpec(sourceShopId, targetShopId), executor);
CompletableFuture<Map<Long, Long>> futureCategory = CompletableFuture.supplyAsync(() -> syncCategory(sourceShopId, targetShopId), executor);
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futureUnit, futureSpec, futureCategory);
allFutures.join();
unitMap = futureUnit.join();
specMap = futureSpec.join();
categoryMap = futureCategory.join();
} catch (Exception e) {
log.error("同步异常", e);
throw new CzgException("同步失败");
}
proMap = syncProduct(sourceShopId, targetShopId, unitMap, specMap, categoryMap);
skuMap = syncSku(sourceShopId, targetShopId, proMap);
syncGroup(sourceShopId, targetShopId, proMap);
syncProductPackage(targetShopId, proMap, skuMap);
//耗材
Map<Long, Long> conGroupMap = syncConsGroup(sourceShopId, targetShopId);
Map<Long, Long> consInfoMap = syncConsInfo(sourceShopId, targetShopId, conGroupMap);
syncConsPro(sourceShopId, targetShopId, consInfoMap, proMap);
}
public Map<Long, Long> syncUnit(Long sourceShopId, Long pointShopId) {
Map<Long, Long> unitMap = new HashMap<>();
List<Long> pointShopUnits = unitService.queryChain().select(ShopProdUnit::getSyncId)
.eq(ShopProdUnit::getShopId, pointShopId)
.isNotNull(ShopProdUnit::getSyncId)
.listAs(Long.class);
List<ShopProdUnit> list = unitService.queryChain().eq(ShopProdUnit::getShopId, sourceShopId).list();
list.forEach(tbShopUnit -> {
if (CollUtil.isEmpty(pointShopUnits) || !pointShopUnits.contains(tbShopUnit.getId())) {
ShopProdUnit unitNew = BeanUtil.copyProperties(tbShopUnit, ShopProdUnit.class);
unitNew.setId(null);
unitNew.setSyncId(tbShopUnit.getId());
unitNew.setShopId(pointShopId);
unitService.save(unitNew);
unitMap.put(tbShopUnit.getId(), unitNew.getId());
}
});
log.info("单位同步,源{}个,已有{}个,同步{}个", list.size(), pointShopUnits.size(), unitMap.size());
return unitMap;
}
//规格
public Map<Long, Long> syncSpec(Long sourceShopId, Long pointShopId) {
Map<Long, Long> specMap = new HashMap<>();
List<Long> pointShopSpecs = specService.queryChain().select(ShopProdSpec::getSyncId)
.eq(ShopProdSpec::getShopId, pointShopId)
.isNotNull(ShopProdSpec::getSyncId)
.listAs(Long.class);
List<ShopProdSpec> list = specService.queryChain().eq(ShopProdSpec::getShopId, sourceShopId.toString()).list();
list.forEach(spec -> {
if (CollUtil.isEmpty(pointShopSpecs) || !pointShopSpecs.contains(spec.getId())) {
ShopProdSpec newSpec = BeanUtil.copyProperties(spec, ShopProdSpec.class);
newSpec.setId(null);
newSpec.setSyncId(spec.getId());
newSpec.setShopId(pointShopId);
specService.save(newSpec);
specMap.put(spec.getId(), newSpec.getId());
}
});
log.info("规格同步,源{}个,已有{}个,同步{}个", list.size(), pointShopSpecs.size(), specMap.size());
return specMap;
}
// 分类
public Map<Long, Long> syncCategory(Long sourceShopId, Long pointShopId) {
Map<Long, Long> categoryMap = new HashMap<>();
List<Long> pointShopCateGory = categoryService.queryChain().select(ShopProdCategory::getSyncId)
.eq(ShopProdCategory::getShopId, pointShopId)
.isNotNull(ShopProdCategory::getSyncId)
.listAs(Long.class);
List<ShopProdCategory> tbShopCategories = categoryService.queryChain()
.eq(ShopProdCategory::getShopId, sourceShopId)
.eq(ShopProdCategory::getPid, 0)
.list();
List<Long> treeIds = new ArrayList<>();
for (ShopProdCategory shopProdCategory : tbShopCategories) {
treeIds.add(shopProdCategory.getId());
if (CollUtil.isEmpty(pointShopCateGory) || !pointShopCateGory.contains(shopProdCategory.getId())) {
ShopProdCategory tbShopCategoryNew = BeanUtil.copyProperties(shopProdCategory, ShopProdCategory.class);
tbShopCategoryNew.setId(null);
tbShopCategoryNew.setShopId(pointShopId);
tbShopCategoryNew.setSyncId(shopProdCategory.getId());
categoryService.save(tbShopCategoryNew);
categoryMap.put(shopProdCategory.getId(), tbShopCategoryNew.getId());
}
}
int childrenSize = 0;
int syncSize = categoryMap.size();
if (CollectionUtil.isNotEmpty(treeIds)) {
List<ShopProdCategory> children = categoryService.queryChain()
.eq(ShopProdCategory::getShopId, sourceShopId)
.in(ShopProdCategory::getPid, treeIds)
.list();
childrenSize = children.size();
for (ShopProdCategory child : children) {
if (CollUtil.isEmpty(pointShopCateGory) || !pointShopCateGory.contains(child.getId())) {
ShopProdCategory tbShopCategoryNew = BeanUtil.copyProperties(child, ShopProdCategory.class);
tbShopCategoryNew.setId(null);
tbShopCategoryNew.setShopId(pointShopId);
tbShopCategoryNew.setSyncId(child.getId());
tbShopCategoryNew.setPid(categoryMap.get(child.getPid()));
categoryService.save(tbShopCategoryNew);
categoryMap.put(child.getId(), tbShopCategoryNew.getId());
}
}
}
log.info("分类同步,源 父类分类{}个,同步{}个", tbShopCategories.size(), syncSize);
log.info("分类同步,源 子类分类{}个,同步{}个", childrenSize, categoryMap.size() - syncSize);
return categoryMap;
}
public Map<Long, Long> syncProduct(Long sourceShopId, Long pointShopId, Map<Long, Long> unitMap,
Map<Long, Long> specMap, Map<Long, Long> cateGoryMap) {
List<Long> pointProducts = productService.queryChain()
.eq(Product::getShopId, pointShopId)
.isNotNull(Product::getSyncId)
.listAs(Long.class);
Map<Long, Long> proMap = new HashMap<>();
List<Product> products = productService.queryChain().eq(Product::getShopId, sourceShopId).list();
if (CollectionUtil.isNotEmpty(products)) {
for (Product tbProduct : products) {
if (CollUtil.isEmpty(pointProducts) || !pointProducts.contains(tbProduct.getId())) {
Product tbProductNew = BeanUtil.copyProperties(tbProduct, Product.class);
tbProductNew.setId(null);
tbProductNew.setSyncId(tbProduct.getId());
tbProductNew.setShopId(pointShopId);
tbProductNew.setCategoryId(tbProduct.getCategoryId() != null ? cateGoryMap.get(tbProduct.getSpecId()) : null);
tbProductNew.setSpecId(tbProduct.getSpecId() != null ? specMap.get(tbProduct.getSpecId()) : null);
tbProductNew.setUnitId(tbProduct.getUnitId() != null ? unitMap.get(tbProduct.getUnitId()) : null);
tbProductNew.setStockNumber(0);
if (CollUtil.isNotEmpty(pointProducts)) {
tbProductNew.setIsSale(0);
}
productService.save(tbProductNew);
proMap.put(tbProduct.getId(), tbProductNew.getId());
}
}
}
log.info("商品同步,源{}个,已有{}个,同步{}个", products.size(), pointProducts.size(), proMap.size());
return proMap;
}
public Map<Long, Long> syncGroup(Long sourceShopId, Long pointShopId, Map<Long, Long> pros) {
Map<Long, Long> groupMap = new HashMap<>();
List<Long> pointGroup = groupService.queryChain().select(ProdGroup::getSyncId).eq(ProdGroup::getShopId, pointShopId)
.isNotNull(ProdGroup::getSyncId).listAs(Long.class);
List<ProdGroup> list = groupService.queryChain().eq(ProdGroup::getShopId, sourceShopId).list();
for (ProdGroup prodGroup : list) {
if (CollUtil.isEmpty(pointGroup) || !pointGroup.contains(prodGroup.getId())) {
ProdGroup tbProductGroupNew = BeanUtil.copyProperties(prodGroup, ProdGroup.class);
tbProductGroupNew.setId(null);
tbProductGroupNew.setSyncId(prodGroup.getId());
tbProductGroupNew.setShopId(pointShopId);
groupService.save(tbProductGroupNew);
groupMap.put(prodGroup.getId(), tbProductGroupNew.getId());
}
}
List<ProdGroupRelation> groupRelations = prodGroupRelationService.queryChain().in(ProdGroupRelation::getProdGroupId, groupMap.keySet()).list();
for (ProdGroupRelation prodGroupRelation : groupRelations) {
prodGroupRelation.setProdGroupId(groupMap.get(prodGroupRelation.getProdGroupId()));
prodGroupRelation.setProductId(pros.get(prodGroupRelation.getProductId()));
}
prodGroupRelationService.saveOrUpdateBatch(groupRelations, 100);
log.info("分组同步,源{}个,已有{}个,同步{}个", list.size(), pointGroup.size(), groupMap.size());
return groupMap;
}
//分组
public void syncProductPackage(Long shopId, Map<Long, Long> pros, Map<Long, Long> skus) {
List<Product> list = productService.queryChain()
.eq(Product::getShopId, shopId)
.and(column(Product::getType).eq("weight").or(column(Product::getType).eq("coupon")))
.list();
for (Product product : list) {
if (StrUtil.isNotBlank(product.getGroupSnap()) && product.getGroupSnap().length() > 5) {
ProductGroupVo proGroupVo = JSONObject.parseObject(product.getGroupSnap(), ProductGroupVo.class);
List<ProductGroupVo.Food> goodList = new ArrayList<>();
for (ProductGroupVo.Food goods : proGroupVo.getGoods()) {
if (pros.containsKey(goods.getProId())) {
if (goods.getSkuId() != null && skus.containsKey(goods.getSkuId())) {
goods.setProId(pros.get(goods.getProId()));
goods.setSkuId(skus.get(goods.getSkuId()));
} else {
goods.setProId(pros.get(goods.getProId()));
}
goodList.add(goods);
}
}
proGroupVo.setCount(goodList.size());
proGroupVo.setGoods(goodList);
if (proGroupVo.getNumber() != null && proGroupVo.getNumber() > 0) {
if (proGroupVo.getNumber() > proGroupVo.getCount()) {
proGroupVo.setNumber(proGroupVo.getCount());
}
}
}
}
}
//分组
public Map<Long, Long> syncSku(Long sourceShopId, Long pointShopId, Map<Long, Long> prods) {
Map<Long, Long> skuMap = new HashMap<>();
List<Long> pointSkus = skuService.queryChain().select(ProdSku::getSyncId)
.eq(ProdSku::getShopId, pointShopId)
.isNotNull(ProdSku::getSyncId)
.listAs(Long.class);
List<ProdSku> list = skuService.queryChain().eq(ProdSku::getShopId, sourceShopId).list();
for (ProdSku prodSku : list) {
if (prods.containsKey(prodSku.getProductId()) && (CollUtil.isEmpty(pointSkus) || !pointSkus.contains(prodSku.getId()))) {
ProdSku newSku = BeanUtil.copyProperties(prodSku, ProdSku.class);
newSku.setId(null);
newSku.setShopId(pointShopId);
newSku.setProductId(prods.get(prodSku.getProductId()));
newSku.setSyncId(prodSku.getId());
skuService.save(newSku);
skuMap.put(prodSku.getId(), newSku.getId());
}
}
log.info("商品SKU同步,源{}个,已有{}个,同步{}个", list.size(), pointSkus.size(), skuMap.size());
return skuMap;
}
public Map<Long, Long> syncConsGroup(Long sourceShopId, Long pointShopId) {
Map<Long, Long> consGroupMap = new HashMap<>();
List<Long> pointConsGroup = consGroupService.queryChain().select(ConsGroup::getSyncId)
.eq(ConsGroup::getShopId, pointShopId)
.isNotNull(ConsGroup::getSyncId)
.listAs(Long.class);
List<ConsGroup> list = consGroupService.queryChain().eq(ConsGroup::getShopId, sourceShopId).list();
for (ConsGroup consGroup : list) {
if (CollUtil.isEmpty(pointConsGroup) || !pointConsGroup.contains(consGroup.getId())) {
ConsGroup newConsGroup = BeanUtil.copyProperties(consGroup, ConsGroup.class);
newConsGroup.setId(null);
newConsGroup.setSyncId(consGroup.getId());
newConsGroup.setShopId(pointShopId);
consGroupService.save(newConsGroup);
consGroupMap.put(consGroup.getId(), newConsGroup.getId());
}
}
log.info("耗材分组同步,源{}个,已有{}个,同步{}个", list.size(), pointConsGroup.size(), consGroupMap.size());
return consGroupMap;
}
// 耗材
public Map<Long, Long> syncConsInfo(Long sourceShopId, Long pointShopId, Map<Long, Long> consGroupMap) {
Map<Long, Long> consMap = new HashMap<>();
List<Long> pointConsInfo = consInfoService.queryChain().select(ConsInfo::getSyncId)
.eq(ConsInfo::getShopId, pointShopId)
.isNotNull(ConsInfo::getSyncId)
.listAs(Long.class);
List<ConsInfo> list = consInfoService.queryChain().eq(ConsInfo::getShopId, sourceShopId).list();
for (ConsInfo cons : list) {
if (CollUtil.isEmpty(pointConsInfo) || !pointConsInfo.contains(cons.getId())) {
ConsInfo conInfo = BeanUtil.copyProperties(cons, ConsInfo.class);
conInfo.setId(null);
conInfo.setShopId(pointShopId);
conInfo.setSyncId(cons.getId());
conInfo.setConsGroupId(consGroupMap.get(conInfo.getConsGroupId()));
conInfo.setStockNumber(BigDecimal.ZERO);
consInfoService.save(conInfo);
consMap.put(cons.getId(), conInfo.getId());
}
}
log.info("耗材同步,源{}个,已有{}个,同步{}个", list.size(), pointConsInfo.size(), consMap.size());
return consMap;
}
public void syncConsPro(Long sourceShopId, Long pointShopId, Map<Long, Long> consMap, Map<Long, Long> proMap) {
List<ProdConsRelation> list = prodConsRelationService.queryChain().eq(ProdConsRelation::getShopId, sourceShopId).list();
for (ProdConsRelation prodConsRelation : list) {
prodConsRelation.setShopId(pointShopId);
prodConsRelation.setProductId(proMap.get(prodConsRelation.getProductId()));
prodConsRelation.setConsInfoId(consMap.get(prodConsRelation.getConsInfoId()));
}
prodConsRelationService.saveOrUpdateBatch(list, 100);
log.info("耗材与商品关联关系,同步{}个", list.size());
}
}