diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/FhbController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/FhbController.java index c48784c8a..5a2ce6cf9 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/FhbController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/FhbController.java @@ -11,7 +11,6 @@ import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbCusDiscountVO; import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbCusVO; import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbProdStockVO; import com.ruoyi.web.controller.xkt.migartion.vo.fhb.FhbProdVO; -import com.ruoyi.xkt.service.shipMaster.IShipMasterService; import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; @@ -33,7 +32,6 @@ import java.util.stream.Collectors; @RequestMapping("/rest/v1/fhb") public class FhbController extends BaseController { - final IShipMasterService shipMasterService; final RedisCache redisCache; /** @@ -130,11 +128,12 @@ public class FhbController extends BaseController { /** * step5 + * * @return */ @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") @GetMapping("/error/cus/disc/{supplierId}") - public R getErrorCusDisc(@PathVariable Integer supplierId){ + public R getErrorCusDisc(@PathVariable Integer supplierId) { // 先从redis中获取列表数据 List cacheList = ObjectUtils.defaultIfNull(redisCache .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_CUS_DISCOUNT_KEY + supplierId), new ArrayList<>()); @@ -168,11 +167,9 @@ public class FhbController extends BaseController { } - // ====================================================================================================================================== - @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") @PostMapping("/colors/cache/{supplierId}") public R createColorsCache(@PathVariable Integer supplierId) { diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java index 1acd75fde..57889c5a6 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndFhbBizController.java @@ -31,7 +31,6 @@ import com.ruoyi.xkt.enums.EProductStatus; import com.ruoyi.xkt.enums.ListingType; import com.ruoyi.xkt.mapper.*; import com.ruoyi.xkt.service.IPictureService; -import com.ruoyi.xkt.service.shipMaster.IShipMasterService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -66,7 +65,6 @@ import static com.ruoyi.common.constant.Constants.WEIGHT_DEFAULT_ZERO; @RequestMapping("/rest/v1/gt-fhb") public class GtAndFhbBizController extends BaseController { - final IShipMasterService shipMasterService; final RedisCache redisCache; final StoreProductColorMapper prodColorMapper; final StoreProductColorSizeMapper prodColorSizeMapper; @@ -846,7 +844,8 @@ public class GtAndFhbBizController extends BaseController { /** * 初始化档口颜色 - * @param storeId 档口ID + * + * @param storeId 档口ID * @param supplierId 供应商ID */ private void initStoreColorList(Long storeId, Integer supplierId) { @@ -887,7 +886,4 @@ public class GtAndFhbBizController extends BaseController { } - - - } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBiz2Controller.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBiz2Controller.java index 2a5c43844..f6ecd3434 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBiz2Controller.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBiz2Controller.java @@ -1,5 +1,8 @@ package com.ruoyi.web.controller.xkt.migartion; +import co.elastic.clients.elasticsearch.core.BulkResponse; +import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; +import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; @@ -9,7 +12,10 @@ import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.framework.es.EsClientWrapper; +import com.ruoyi.framework.notice.fs.FsNotice; import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYCompareDownloadVO; import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYInitVO; import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtCateVO; @@ -19,11 +25,13 @@ import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyCusImportVO; import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdImportVO; import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdStockVO; import com.ruoyi.xkt.domain.*; +import com.ruoyi.xkt.dto.es.ESProductDTO; +import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdMinPriceDTO; import com.ruoyi.xkt.enums.EProductStatus; import com.ruoyi.xkt.enums.ListingType; import com.ruoyi.xkt.mapper.*; -import com.ruoyi.xkt.service.shipMaster.IShipMasterService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; @@ -34,23 +42,26 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; import java.net.URLEncoder; import java.time.LocalDate; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import static com.ruoyi.common.constant.Constants.WEIGHT_DEFAULT_ZERO; + /** * Compare 相关 处理主要是 匹配非常贴近的数据 * * @author ruoyi */ +@Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/rest/v1/gt-ty/t2") public class GtAndTyBiz2Controller extends BaseController { - final IShipMasterService shipMasterService; final RedisCache redisCache; final StoreProductColorMapper prodColorMapper; final StoreProductColorSizeMapper prodColorSizeMapper; @@ -63,34 +74,8 @@ public class GtAndTyBiz2Controller extends BaseController { final StoreProductServiceMapper prodSvcMapper; final StoreProductCategoryAttributeMapper prodCateAttrMapper; final SysProductCategoryMapper prodCateMapper; - - - // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 - // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 - // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 - - - @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @PostMapping("/sync-es/{storeId}") - public void syncToEs(@PathVariable("storeId") Long storeId) { - // 同步主图 到 图搜 服务器 - - // TODO 上传到ES之后还需要确认 - // TODO 上传到ES之后还需要确认 - // TODO 上传到ES之后还需要确认 - - } - - @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @PostMapping("/sync-pic/{storeId}") - public void syncToPicSearch(@PathVariable("storeId") Long storeId) { - // 同步主图 到 图搜 服务器 - - // TODO 上传到图搜服务器之后还要确认 - // TODO 上传到图搜服务器之后还要确认 - // TODO 上传到图搜服务器之后还要确认 - - } + final EsClientWrapper esClientWrapper; + final FsNotice fsNotice; /** @@ -357,15 +342,6 @@ public class GtAndTyBiz2Controller extends BaseController { return R.ok(); } - - - - - - - - - /** * step4 */ @@ -381,33 +357,43 @@ public class GtAndTyBiz2Controller extends BaseController { List storeCusList = this.storeCusMapper.selectList(new LambdaQueryWrapper() .eq(StoreCustomer::getStoreId, initVO.getStoreId()).eq(StoreCustomer::getDelFlag, Constants.UNDELETED)); - Map> multiSameTyMap = new HashMap<>(); - // 查看TY 这边有多少相似的货号 - List tyProdList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()); - tyProdList.stream().map(TyProdImportVO::getProdArtNum).distinct() - .forEach(artNo -> { - // 只保留核心连续的数字,去除其他所有符号 - String cleanArtNo = this.extractCoreArticleNumber(artNo); - if (CollectionUtils.isEmpty(initVO.getExcludeArtNoList()) || !initVO.getExcludeArtNoList().contains(cleanArtNo)) { - List existList = multiSameTyMap.containsKey(cleanArtNo) ? multiSameTyMap.get(cleanArtNo) : new ArrayList<>(); - existList.add(artNo); - multiSameTyMap.put(cleanArtNo, existList); - } - }); + // 处理的思路,以GT为主,根据GT的货号 去匹配TY的货号,有些档口写的比较规范,这种就比较好处理 + List gtOnSaleList = ObjectUtils.defaultIfNull(redisCache.getCacheObject(CacheConstants.MIGRATION_GT_SALE_BASIC_KEY + initVO.getUserId()), new ArrayList<>()); + // gt所有在售的货号列表 + List gtArtNoList = gtOnSaleList.stream().map(GtProdSkuVO::getArticle_number).map(String::trim).distinct().collect(Collectors.toList()); - // TY商品缓存 - List cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()); - if (CollectionUtils.isEmpty(cacheList)) { + // 找到TY对应的商品 + List tyProdList = ObjectUtils.defaultIfNull(redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()), new ArrayList<>()); + if (CollectionUtils.isEmpty(tyProdList)) { throw new ServiceException("TY商品列表为空", HttpStatus.ERROR); } // ty货号正在生效的颜色map,因为客户优惠有些是删除的颜色,需要通过这里去过滤 - Map> tyExistArtNoColorMap = cacheList.stream().collect(Collectors + Map> tyExistArtNoColorMap = tyProdList.stream().collect(Collectors .groupingBy(TyProdImportVO::getProdArtNum, Collectors.mapping(TyProdImportVO::getColorName, Collectors.toSet()))); + // TY货号下颜色的map + Map tyArtNoColorMap = tyProdList.stream().collect(Collectors.groupingBy(TyProdImportVO::getProdArtNum, + Collectors.collectingAndThen(Collectors.mapping(TyProdImportVO::getColorName, Collectors.toList()), + list -> "(" + list.stream().distinct().collect(Collectors.joining(",")) + ")"))); + + // GT和TY匹配的货号map + Map> gtMatchTyArtNoMap = new HashMap<>(); + // 以GT为准在,找TY匹配的货号 + gtArtNoList.forEach(gtOnSaleArtNo -> tyArtNoColorMap.forEach((tyArtNo, tyArtNoColorStr) -> { + if (tyArtNo.contains(gtOnSaleArtNo)) { + List existMatchArtNoList = gtMatchTyArtNoMap.getOrDefault(gtOnSaleArtNo, new ArrayList<>()); + existMatchArtNoList.add(tyArtNo); + gtMatchTyArtNoMap.put(gtOnSaleArtNo, existMatchArtNoList); + } + })); + // 从redis中获取已存在的客户优惠数据 List tyCusDiscCacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_DISCOUNT_KEY + initVO.getUserId()); if (CollectionUtils.isEmpty(tyCusDiscCacheList)) { throw new ServiceException("ty供应商客户优惠列表为空!" + initVO.getUserId(), HttpStatus.ERROR); } + // 增加一重保险,客户优惠必须大于0 + tyCusDiscCacheList = tyCusDiscCacheList.stream().filter(x -> x.getDiscount() > 0).collect(Collectors.toList()); + // 从redis中获取已存在的商品库存数据 List tyStockList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_STOCK_KEY + initVO.getUserId()); if (CollectionUtils.isEmpty(tyStockList)) { @@ -428,11 +414,10 @@ public class GtAndTyBiz2Controller extends BaseController { List prodStockList = new ArrayList<>(); // 依次遍历商品列表,找到货号和FHB货号对应关系,然后用颜色进行匹配,建立客户优惠关系 storeProdList.forEach(storeProd -> { - final String cleanArtNo = this.extractCoreArticleNumber(storeProd.getProdArtNum()); // 当前商品颜色列表 key 颜色中文名称 Map buJuProdColorMap = Optional.ofNullable(prodColorGroupMap.get(storeProd.getId())).orElseThrow(() -> new ServiceException("没有商品颜色!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); // 根据步橘货号 找到TY对应的货号,可能是列表 - List tyAtrNoList = Optional.ofNullable(multiSameTyMap.get(cleanArtNo)).orElseThrow(() -> new ServiceException("没有TY货号!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); + List tyAtrNoList = Optional.ofNullable(gtMatchTyArtNoMap.get(storeProd.getProdArtNum())).orElseThrow(() -> new ServiceException("没有TY货号!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); // 处理档口商品库存 this.handleProdStock(tyAtrNoList, tyProdStockMap, buJuProdColorMap, storeProd.getStoreId(), storeProd.getId(), storeProd.getProdArtNum(), prodStockList); @@ -451,6 +436,88 @@ public class GtAndTyBiz2Controller extends BaseController { return R.ok(); } + /** + * step5 + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @PostMapping("/sync-es/{storeId}") + public R syncToEs(@PathVariable("storeId") Long storeId) { + // 将公共的商品同步到ES + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, storeId)); + if (CollectionUtils.isEmpty(storeProdList)) { + return R.fail(); + } + final List storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList()); + // 所有的分类 + List prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper() + .eq(SysProductCategory::getDelFlag, Constants.UNDELETED)); + Map prodCateMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getId, x -> x)); + // 获取当前商品最低价格 + Map prodMinPriceMap = this.prodColorSizeMapper.selectStoreProdMinPriceList(storeProdIdList).stream().collect(Collectors + .toMap(StoreProdMinPriceDTO::getStoreProdId, StoreProdMinPriceDTO::getPrice)); + // 档口商品的属性map + Map cateAttrMap = this.prodCateAttrMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).in(StoreProductCategoryAttribute::getStoreProdId, storeProdIdList)) + .stream().collect(Collectors.toMap(StoreProductCategoryAttribute::getStoreProdId, x -> x)); + // 档口商品对应的档口 + Map storeMap = this.storeMapper.selectList(new LambdaQueryWrapper().eq(Store::getDelFlag, Constants.UNDELETED) + .in(Store::getId, storeProdList.stream().map(StoreProduct::getStoreId).collect(Collectors.toList()))) + .stream().collect(Collectors.toMap(Store::getId, x -> x)); + List esProductDTOList = new ArrayList<>(); + for (StoreProduct product : storeProdList) { + final SysProductCategory cate = prodCateMap.get(product.getProdCateId()); + final SysProductCategory parCate = ObjectUtils.isEmpty(cate) ? null : prodCateMap.get(cate.getParentId()); + final Store store = storeMap.get(product.getStoreId()); + final BigDecimal prodMinPrice = prodMinPriceMap.get(product.getId()); + final StoreProductCategoryAttribute cateAttr = cateAttrMap.get(product.getId()); + ESProductDTO esProductDTO = new ESProductDTO().setStoreProdId(product.getId().toString()).setProdArtNum(product.getProdArtNum()) + .setHasVideo(Boolean.FALSE).setProdCateId(product.getProdCateId().toString()).setCreateTime(DateUtils.getTime()) + .setProdCateName(ObjectUtils.isNotEmpty(cate) ? cate.getName() : "") + .setSaleWeight(WEIGHT_DEFAULT_ZERO.toString()).setRecommendWeight(WEIGHT_DEFAULT_ZERO.toString()) + .setPopularityWeight(WEIGHT_DEFAULT_ZERO.toString()) + .setMainPicUrl("").setMainPicName("").setMainPicSize(BigDecimal.ZERO) + .setParCateId(ObjectUtils.isNotEmpty(parCate) ? parCate.getId().toString() : "") + .setParCateName(ObjectUtils.isNotEmpty(parCate) ? parCate.getName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(prodMinPrice) ? prodMinPrice.toString() : "") + .setSeason(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getSuitableSeason() : "") + .setProdStatus(product.getProdStatus().toString()) + .setStoreId(product.getStoreId().toString()) + .setStoreName(ObjectUtils.isNotEmpty(store) ? store.getStoreName() : "") + .setStyle(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getStyle() : "") + .setProdTitle(product.getProdTitle()); + if (ObjectUtils.isNotEmpty(cateAttr) && StringUtils.isNotBlank(cateAttr.getStyle())) { + esProductDTO.setTags(Collections.singletonList(cateAttr.getStyle())); + } + esProductDTOList.add(esProductDTO); + } + // 构建批量操作请求 + List bulkOperations = new ArrayList<>(); + for (ESProductDTO esProductDTO : esProductDTOList) { + BulkOperation bulkOperation = new BulkOperation.Builder() + .index(i -> i.id(esProductDTO.getStoreProdId()).index(Constants.ES_IDX_PRODUCT_INFO).document(esProductDTO)) + .build(); + bulkOperations.add(bulkOperation); + } + // 执行批量插入 + try { + BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(Constants.ES_IDX_PRODUCT_INFO).operations(bulkOperations)); + log.info("批量新增到 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList())); + // 有哪些没执行成功的,需要发飞书通知 + List successIdList = response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList()); + List unExeIdList = storeProdIdList.stream().map(String::valueOf).filter(x -> !successIdList.contains(x)).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(unExeIdList)) { + fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", "以下storeProdId未执行成功: " + unExeIdList); + } else { + fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 成功", "共处理 " + response.items().size() + " 条记录"); + } + } catch (Exception e) { + log.error("批量新增到 ES 失败", e); + fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", e.getMessage()); + } + return R.ok(); + } + /** * 初始化系统颜色 @@ -509,8 +576,7 @@ public class GtAndTyBiz2Controller extends BaseController { /** * 处理档口客户优惠 */ - private void handleCusDisc(String tyAtrNo, Map> tyExistArtNoColorMap, - Map>> tyCusDiscGroupMap, + private void handleCusDisc(String tyAtrNo, Map> tyExistArtNoColorMap, Map>> tyCusDiscGroupMap, Map buJuProdColorMap, Map buJuStoreCusMap, List prodCusDiscList, Long storeId, Long storeProdId) { // TY货号下有哪些颜色存在客户优惠 @@ -529,7 +595,7 @@ public class GtAndTyBiz2Controller extends BaseController { // TODO 该处TY 与 FHB处理不同 // TODO 该处TY 与 FHB处理不同 // TODO 该处TY 与 FHB处理不同 - tyCusDiscList.forEach(tyCusDisc -> { + tyCusDiscList.stream().filter(x -> x.getDiscount() > 0).forEach(tyCusDisc -> { StoreProductColor buJuProdColor = Optional.ofNullable(buJuProdColorMap.get(tyColor)).orElseThrow(() -> new ServiceException("没有步橘系统对应的颜色!" + tyColor, HttpStatus.ERROR)); StoreCustomer storeCus = Optional.ofNullable(buJuStoreCusMap.get(tyCusDisc.getCusName())).orElseThrow(() -> new ServiceException("没有步橘系统对应的客户!" + tyCusDisc.getCusName(), HttpStatus.ERROR)); // 将FHB客户优惠 转为步橘系统优惠 @@ -543,9 +609,8 @@ public class GtAndTyBiz2Controller extends BaseController { * 初始化客户列表 * * @param initVO 入参 - * @return List */ - private List initStoreCusList(GtAndTYInitVO initVO) { + private void initStoreCusList(GtAndTYInitVO initVO) { List cacheList = ObjectUtils.defaultIfNull(redisCache .getCacheObject(CacheConstants.MIGRATION_TY_CUS_KEY + initVO.getUserId()), new ArrayList<>()); if (CollectionUtils.isEmpty(cacheList)) { @@ -557,7 +622,6 @@ public class GtAndTyBiz2Controller extends BaseController { .map(x -> new StoreCustomer().setStoreId(initVO.getStoreId()).setCusName(x.getCusName())) .collect(Collectors.toList()); this.storeCusMapper.insert(storeCusList); - return storeCusList; } /** @@ -674,45 +738,4 @@ public class GtAndTyBiz2Controller extends BaseController { prodAttrMap.put(product_id, prodAttr); } - /** - * 取GT匹配的多个货号中的第一个商品 - * - * @param multiSaleSameGoMap - * @param gtSaleGroupMap - * @param cleanArtNo - * @return - */ - private List getGtFirstSku(Map> multiSaleSameGoMap, Map> gtSaleGroupMap, String cleanArtNo) { - // GT匹配的货号 - List gtMatchArtNoList = multiSaleSameGoMap.get(cleanArtNo); - // GT 最短的货号 - String shortestArtNo = gtMatchArtNoList.stream().min(Comparator.comparingInt(String::length)) - .orElse(gtMatchArtNoList.get(0)); - return gtSaleGroupMap.get(shortestArtNo); - } - - - /** - * 提取货号中的核心数字部分 - * 例如: z1104 -> 1104, z1087高 -> 1087, z1003-1 -> 1003, 922- -> 922, -8072 -> 8072 - * - * @param articleNumber 货号 - * @return 核心数字部分 - */ - private String extractCoreArticleNumber(String articleNumber) { - if (articleNumber == null || articleNumber.isEmpty()) { - return ""; - } - // 使用正则表达式匹配第一组连续的数字 - java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\d+"); - java.util.regex.Matcher matcher = pattern.matcher(articleNumber); - // 返回第一组匹配到的数字 - if (matcher.find()) { - return matcher.group(); - } - // 如果没有找到数字,返回空字符串 - throw new ServiceException("货号格式错误", HttpStatus.ERROR); - } - - } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBizController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBizController.java index 842df6c1d..bf1e7fd7e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBizController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBizController.java @@ -1,5 +1,8 @@ package com.ruoyi.web.controller.xkt.migartion; +import co.elastic.clients.elasticsearch.core.BulkResponse; +import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; +import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.Constants; @@ -9,7 +12,10 @@ import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.framework.es.EsClientWrapper; +import com.ruoyi.framework.notice.fs.FsNotice; import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYCompareDownloadVO; import com.ruoyi.web.controller.xkt.migartion.vo.GtAndTYInitVO; import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtCateVO; @@ -19,11 +25,13 @@ import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyCusImportVO; import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdImportVO; import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdStockVO; import com.ruoyi.xkt.domain.*; +import com.ruoyi.xkt.dto.es.ESProductDTO; +import com.ruoyi.xkt.dto.storeProdColorPrice.StoreProdMinPriceDTO; import com.ruoyi.xkt.enums.EProductStatus; import com.ruoyi.xkt.enums.ListingType; import com.ruoyi.xkt.mapper.*; -import com.ruoyi.xkt.service.shipMaster.IShipMasterService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; @@ -34,23 +42,26 @@ import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; import java.net.URLEncoder; import java.time.LocalDate; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import static com.ruoyi.common.constant.Constants.WEIGHT_DEFAULT_ZERO; + /** * Compare 相关 * * @author ruoyi */ +@Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/rest/v1/gt-ty") public class GtAndTyBizController extends BaseController { - final IShipMasterService shipMasterService; final RedisCache redisCache; final StoreProductColorMapper prodColorMapper; final StoreProductColorSizeMapper prodColorSizeMapper; @@ -63,34 +74,8 @@ public class GtAndTyBizController extends BaseController { final StoreProductServiceMapper prodSvcMapper; final StoreProductCategoryAttributeMapper prodCateAttrMapper; final SysProductCategoryMapper prodCateMapper; - - - // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 - // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 - // TODO 提供导出测试环境数据的接口,不然迁移到生产还要重新来一遍 - - - @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @PostMapping("/sync-es/{storeId}") - public void syncToEs(@PathVariable("storeId") Long storeId) { - // 同步主图 到 图搜 服务器 - - // TODO 上传到ES之后还需要确认 - // TODO 上传到ES之后还需要确认 - // TODO 上传到ES之后还需要确认 - - } - - @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") - @PostMapping("/sync-pic/{storeId}") - public void syncToPicSearch(@PathVariable("storeId") Long storeId) { - // 同步主图 到 图搜 服务器 - - // TODO 上传到图搜服务器之后还要确认 - // TODO 上传到图搜服务器之后还要确认 - // TODO 上传到图搜服务器之后还要确认 - - } + final EsClientWrapper esClientWrapper; + final FsNotice fsNotice; /** * step1 @@ -485,8 +470,6 @@ public class GtAndTyBizController extends BaseController { }); - - }); // 档口客户优惠 this.storeCusProdDiscMapper.insert(prodCusDiscList); @@ -495,6 +478,88 @@ public class GtAndTyBizController extends BaseController { return R.ok(); } + /** + * step5 + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @PostMapping("/sync-es/{storeId}") + public R syncToEs(@PathVariable("storeId") Long storeId) { + // 将公共的商品同步到ES + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getDelFlag, Constants.UNDELETED).eq(StoreProduct::getStoreId, storeId)); + if (CollectionUtils.isEmpty(storeProdList)) { + return R.fail(); + } + final List storeProdIdList = storeProdList.stream().map(StoreProduct::getId).map(String::valueOf).collect(Collectors.toList()); + // 所有的分类 + List prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper() + .eq(SysProductCategory::getDelFlag, Constants.UNDELETED)); + Map prodCateMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getId, x -> x)); + // 获取当前商品最低价格 + Map prodMinPriceMap = this.prodColorSizeMapper.selectStoreProdMinPriceList(storeProdIdList).stream().collect(Collectors + .toMap(StoreProdMinPriceDTO::getStoreProdId, StoreProdMinPriceDTO::getPrice)); + // 档口商品的属性map + Map cateAttrMap = this.prodCateAttrMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED).in(StoreProductCategoryAttribute::getStoreProdId, storeProdIdList)) + .stream().collect(Collectors.toMap(StoreProductCategoryAttribute::getStoreProdId, x -> x)); + // 档口商品对应的档口 + Map storeMap = this.storeMapper.selectList(new LambdaQueryWrapper().eq(Store::getDelFlag, Constants.UNDELETED) + .in(Store::getId, storeProdList.stream().map(StoreProduct::getStoreId).collect(Collectors.toList()))) + .stream().collect(Collectors.toMap(Store::getId, x -> x)); + List esProductDTOList = new ArrayList<>(); + for (StoreProduct product : storeProdList) { + final SysProductCategory cate = prodCateMap.get(product.getProdCateId()); + final SysProductCategory parCate = ObjectUtils.isEmpty(cate) ? null : prodCateMap.get(cate.getParentId()); + final Store store = storeMap.get(product.getStoreId()); + final BigDecimal prodMinPrice = prodMinPriceMap.get(product.getId()); + final StoreProductCategoryAttribute cateAttr = cateAttrMap.get(product.getId()); + ESProductDTO esProductDTO = new ESProductDTO().setStoreProdId(product.getId().toString()).setProdArtNum(product.getProdArtNum()) + .setHasVideo(Boolean.FALSE).setProdCateId(product.getProdCateId().toString()).setCreateTime(DateUtils.getTime()) + .setProdCateName(ObjectUtils.isNotEmpty(cate) ? cate.getName() : "") + .setSaleWeight(WEIGHT_DEFAULT_ZERO.toString()).setRecommendWeight(WEIGHT_DEFAULT_ZERO.toString()) + .setPopularityWeight(WEIGHT_DEFAULT_ZERO.toString()) + .setMainPicUrl("").setMainPicName("").setMainPicSize(BigDecimal.ZERO) + .setParCateId(ObjectUtils.isNotEmpty(parCate) ? parCate.getId().toString() : "") + .setParCateName(ObjectUtils.isNotEmpty(parCate) ? parCate.getName() : "") + .setProdPrice(ObjectUtils.isNotEmpty(prodMinPrice) ? prodMinPrice.toString() : "") + .setSeason(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getSuitableSeason() : "") + .setProdStatus(product.getProdStatus().toString()) + .setStoreId(product.getStoreId().toString()) + .setStoreName(ObjectUtils.isNotEmpty(store) ? store.getStoreName() : "") + .setStyle(ObjectUtils.isNotEmpty(cateAttr) ? cateAttr.getStyle() : "") + .setProdTitle(product.getProdTitle()); + if (ObjectUtils.isNotEmpty(cateAttr) && StringUtils.isNotBlank(cateAttr.getStyle())) { + esProductDTO.setTags(Collections.singletonList(cateAttr.getStyle())); + } + esProductDTOList.add(esProductDTO); + } + // 构建批量操作请求 + List bulkOperations = new ArrayList<>(); + for (ESProductDTO esProductDTO : esProductDTOList) { + BulkOperation bulkOperation = new BulkOperation.Builder() + .index(i -> i.id(esProductDTO.getStoreProdId()).index(Constants.ES_IDX_PRODUCT_INFO).document(esProductDTO)) + .build(); + bulkOperations.add(bulkOperation); + } + // 执行批量插入 + try { + BulkResponse response = esClientWrapper.getEsClient().bulk(b -> b.index(Constants.ES_IDX_PRODUCT_INFO).operations(bulkOperations)); + log.info("批量新增到 ES 成功的 id列表: {}", response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList())); + // 有哪些没执行成功的,需要发飞书通知 + List successIdList = response.items().stream().map(BulkResponseItem::id).collect(Collectors.toList()); + List unExeIdList = storeProdIdList.stream().map(String::valueOf).filter(x -> !successIdList.contains(x)).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(unExeIdList)) { + fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", "以下storeProdId未执行成功: " + unExeIdList); + } else { + fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 成功", "共处理 " + response.items().size() + " 条记录"); + } + } catch (Exception e) { + log.error("批量新增到 ES 失败", e); + fsNotice.sendMsg2DefaultChat(storeId + ",批量新增商品到 ES 失败", e.getMessage()); + } + return R.ok(); + } + /** * 初始化系统颜色 @@ -573,7 +638,7 @@ public class GtAndTyBizController extends BaseController { // TODO 该处TY 与 FHB处理不同 // TODO 该处TY 与 FHB处理不同 // TODO 该处TY 与 FHB处理不同 - tyCusDiscList.forEach(tyCusDisc -> { + tyCusDiscList.stream().filter(x -> x.getDiscount() > 0).forEach(tyCusDisc -> { StoreProductColor buJuProdColor = Optional.ofNullable(buJuProdColorMap.get(tyColor)).orElseThrow(() -> new ServiceException("没有步橘系统对应的颜色!" + tyColor, HttpStatus.ERROR)); StoreCustomer storeCus = Optional.ofNullable(buJuStoreCusMap.get(tyCusDisc.getCusName())).orElseThrow(() -> new ServiceException("没有步橘系统对应的客户!" + tyCusDisc.getCusName(), HttpStatus.ERROR)); // 将FHB客户优惠 转为步橘系统优惠 diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtController.java index 2c1c3e2cf..13ca75fd5 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtController.java @@ -11,7 +11,6 @@ import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtCateVO; import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtProdSkuVO; import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtProdVO; import com.ruoyi.xkt.mapper.SysProductCategoryMapper; -import com.ruoyi.xkt.service.shipMaster.IShipMasterService; import lombok.RequiredArgsConstructor; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; @@ -21,10 +20,8 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.math.BigDecimal; import java.time.LocalDate; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; /** @@ -37,7 +34,6 @@ import java.util.stream.Collectors; @RequestMapping("/rest/v1/gt") public class GtController extends BaseController { - final IShipMasterService shipMasterService; final RedisCache redisCache; final SysProductCategoryMapper prodCateMapper; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/TyController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/TyController.java index 82ea46316..62e6b40f9 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/TyController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/TyController.java @@ -181,7 +181,7 @@ public class TyController extends BaseController { */ @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") @GetMapping("/error/cus/disc/{userId}") - public R getErrorCusDisc(@PathVariable Integer userId){ + public R getErrorCusDisc(@PathVariable Integer userId) { List cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_DISCOUNT_KEY + userId); List errDiscList = new ArrayList<>(); // 1. 有哪些是优惠价大于销售价的 @@ -226,11 +226,7 @@ public class TyController extends BaseController { if (cusDiscMap.containsKey(cusName)) { throw new ServiceException(cusName + " : 客户已导入过优惠数据", HttpStatus.ERROR); } - - // TODO 临时去掉 - // TODO 临时去掉 - - /* // 判断货号 + 颜色是否存在,“图识”可能不准 + // 判断货号 + 颜色是否存在,“图识”可能不准 List tyProdVOList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + userId); // key prod+colorName Map tyProdColorMap = tyProdVOList.stream().collect(Collectors.toMap(x -> x.getProdArtNum() + ":" + x.getColorName(), x -> x)); @@ -243,11 +239,7 @@ public class TyController extends BaseController { }); if (CollectionUtils.isNotEmpty(errorList)) { throw new ServiceException(errorList.toString(), HttpStatus.ERROR); - }*/ - - - - + } } } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/shipMaster/IShipMasterService.java b/xkt/src/main/java/com/ruoyi/xkt/service/shipMaster/IShipMasterService.java deleted file mode 100644 index 3aea53599..000000000 --- a/xkt/src/main/java/com/ruoyi/xkt/service/shipMaster/IShipMasterService.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.ruoyi.xkt.service.shipMaster; - -/** - * @author ruoyi - */ -public interface IShipMasterService { - - -} diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/shipMaster/impl/ShipMasterServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/shipMaster/impl/ShipMasterServiceImpl.java deleted file mode 100644 index fe0e1611a..000000000 --- a/xkt/src/main/java/com/ruoyi/xkt/service/shipMaster/impl/ShipMasterServiceImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ruoyi.xkt.service.shipMaster.impl; - -import com.ruoyi.xkt.service.shipMaster.IShipMasterService; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -/** - * 公告 - * - * @author ruoyi - */ -@Service -@RequiredArgsConstructor -public class ShipMasterServiceImpl implements IShipMasterService { - - -}