From 802927498bb41460c1128df5a4e4785a41e5dec6 Mon Sep 17 00:00:00 2001 From: liujiang <569804566@qq.com> Date: Thu, 16 Oct 2025 15:49:24 +0800 Subject: [PATCH] =?UTF-8?q?master=EF=BC=9A=E7=B3=BB=E7=BB=9F=E8=B0=83?= =?UTF-8?q?=E4=BC=98=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xkt/migartion/FhbController.java | 47 +- .../xkt/migartion/GtAndFhbBizController.java | 5 +- .../xkt/migartion/GtAndTyBiz2Controller.java | 718 ++++++++++++++++++ .../xkt/migartion/GtAndTyBizController.java | 31 +- .../xkt/migartion/TyController.java | 149 ++-- .../xkt/migartion/vo/CusDiscErrorVO.java | 21 + 6 files changed, 894 insertions(+), 77 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBiz2Controller.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/vo/CusDiscErrorVO.java 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 32c28a806..c48784c8a 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 @@ -6,6 +6,7 @@ import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.web.controller.xkt.migartion.vo.CusDiscErrorVO; 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; @@ -93,20 +94,12 @@ public class FhbController extends BaseController { if (ObjectUtils.isEmpty(cusDiscountVO.getData()) || ObjectUtils.isEmpty(cusDiscountVO.getData().getRecords())) { return R.ok(); } - // 错误的折扣列表 - List errorCusDiscList = new ArrayList<>(); // 设置优惠价格 cusDiscountVO.getData().getRecords().forEach(record -> { final Integer supplyPrice = ObjectUtils.defaultIfNull(record.getSupplyPrice(), 0); final Integer customerPrice = ObjectUtils.defaultIfNull(record.getCustomerPrice(), 0); - if (supplyPrice - customerPrice < 0) { - errorCusDiscList.add(record.getArtNo() + ":" + record.getCustomerName() + ":" + record.getColor()); - } record.setDiscount(supplyPrice - customerPrice); }); - if (CollectionUtils.isNotEmpty(errorCusDiscList)) { - throw new ServiceException("供应商商品价格有误!" + errorCusDiscList, HttpStatus.ERROR); - } // 先从redis中获取列表数据 List cacheList = ObjectUtils.defaultIfNull(redisCache .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_CUS_DISCOUNT_KEY + supplierId), new ArrayList<>()); @@ -135,6 +128,44 @@ public class FhbController extends BaseController { return R.ok(); } + /** + * step5 + * @return + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @GetMapping("/error/cus/disc/{supplierId}") + public R getErrorCusDisc(@PathVariable Integer supplierId){ + // 先从redis中获取列表数据 + List cacheList = ObjectUtils.defaultIfNull(redisCache + .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_CUS_DISCOUNT_KEY + supplierId), new ArrayList<>()); + if (CollectionUtils.isEmpty(cacheList)) { + return R.ok(); + } + List errDiscList = new ArrayList<>(); + // 1. 有哪些是优惠价大于销售价的 + cacheList.forEach(record -> { + final Integer supplyPrice = ObjectUtils.defaultIfNull(record.getSupplyPrice(), 0); + final Integer customerPrice = ObjectUtils.defaultIfNull(record.getCustomerPrice(), 0); + if (supplyPrice - customerPrice <= 0) { + errDiscList.add(record.getArtNo() + ":" + record.getCustomerName() + ":" + record.getColor() + ",优惠价大于原售价"); + } + }); + // 2. 有哪些优惠是同一货号不同颜色优惠金额不一致 + List errCusDiscUnSameList = new ArrayList<>(); + Map>> artNoCusDiscMap = cacheList.stream().collect(Collectors + .groupingBy(FhbCusDiscountVO.SMCDRecordVO::getArtNo, Collectors.groupingBy(FhbCusDiscountVO.SMCDRecordVO::getCustomerName))); + artNoCusDiscMap.forEach((artNo, cusDiscMap) -> cusDiscMap.forEach((cusName, cusDiscList) -> { + Map colorDiscMap = cusDiscList.stream().collect(Collectors.groupingBy(FhbCusDiscountVO.SMCDRecordVO::getColor, + Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(FhbCusDiscountVO.SMCDRecordVO::getUpdateTime, + Comparator.nullsFirst(String::compareTo))), record -> record.get().getDiscount()))); + // 判断所有颜色的优惠金额是否一致 + Set discValueSet = new HashSet<>(colorDiscMap.values()); + if (discValueSet.size() > 1) { + errCusDiscUnSameList.add(artNo + ":" + cusName + ":" + colorDiscMap.keySet() + ",优惠金额不一致"); + } + })); + return R.ok(new CusDiscErrorVO().setErrDiscList(errDiscList).setErrCusDiscUnSameList(errCusDiscUnSameList)); + } 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 9302e66bb..1acd75fde 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 @@ -311,8 +311,7 @@ public class GtAndFhbBizController extends BaseController { prodSvcList.add(new StoreProductService().setStoreProdId(storeProd.getId()).setCustomRefund("0") .setThirtyDayRefund("0").setOneBatchSale("1").setRefundWithinThreeDay("0")); // 初始化商品的类目属性 - StoreProductCategoryAttribute cateAttr = Optional.ofNullable(prodAttrMap.get(gtMatchSkuList.get(0).getProduct_id())) - .orElseThrow(() -> new ServiceException("没有GT商品类目属性!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); + StoreProductCategoryAttribute cateAttr = Optional.ofNullable(prodAttrMap.get(gtMatchSkuList.get(0).getProduct_id())).orElse(new StoreProductCategoryAttribute()); cateAttr.setStoreId(storeProd.getStoreId()).setStoreProdId(storeProd.getId()); prodAttrList.add(cateAttr); }); @@ -491,6 +490,8 @@ public class GtAndFhbBizController extends BaseController { if (CollectionUtils.isEmpty(fhbCusDiscCacheList)) { throw new ServiceException("fhb供应商客户优惠列表为空!" + initVO.getSupplierId(), HttpStatus.ERROR); } + // 2025.10.16 增加一重保险,客户优惠必须是大于0的 + fhbCusDiscCacheList = fhbCusDiscCacheList.stream().filter(x -> x.getDiscount() > 0).collect(Collectors.toList()); List fhbStockCacheList = redisCache .getCacheObject(CacheConstants.MIGRATION_SUPPLIER_PROD_STOCK_KEY + initVO.getSupplierId()); if (CollectionUtils.isEmpty(fhbStockCacheList)) { 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 new file mode 100644 index 000000000..2a5c43844 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/GtAndTyBiz2Controller.java @@ -0,0 +1,718 @@ +package com.ruoyi.web.controller.xkt.migartion; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.ruoyi.common.constant.CacheConstants; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.HttpStatus; +import com.ruoyi.common.core.controller.BaseController; +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.poi.ExcelUtil; +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; +import com.ruoyi.web.controller.xkt.migartion.vo.gt.GtProdSkuVO; +import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyCusDiscImportVO; +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.enums.EProductStatus; +import com.ruoyi.xkt.enums.ListingType; +import com.ruoyi.xkt.mapper.*; +import com.ruoyi.xkt.service.shipMaster.IShipMasterService; +import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.time.LocalDate; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +/** + * Compare 相关 处理主要是 匹配非常贴近的数据 + * + * @author ruoyi + */ +@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; + final StoreProductMapper storeProdMapper; + final StoreProductStockMapper prodStockMapper; + final StoreCustomerMapper storeCusMapper; + final StoreCustomerProductDiscountMapper storeCusProdDiscMapper; + final StoreColorMapper storeColorMapper; + final StoreMapper storeMapper; + 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 上传到图搜服务器之后还要确认 + + } + + + /** + * step1 + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @GetMapping("/compare/{userId}") + public void compare(HttpServletResponse response, @PathVariable("userId") Integer userId) throws UnsupportedEncodingException { + // 处理的思路,以GT为主,根据GT的货号 去匹配TY的货号,有些档口写的比较规范,这种就比较好处理 + List gtOnSaleList = ObjectUtils.defaultIfNull(redisCache + .getCacheObject(CacheConstants.MIGRATION_GT_SALE_BASIC_KEY + userId), new ArrayList<>()); + // gt所有在售的货号列表 + List gtArtNoList = gtOnSaleList.stream().map(GtProdSkuVO::getArticle_number).map(String::trim).distinct().collect(Collectors.toList()); + Map gtOnSaleArtNoColorMap = gtOnSaleList.stream().collect(Collectors.groupingBy(GtProdSkuVO::getArticle_number, + Collectors.collectingAndThen(Collectors.mapping(GtProdSkuVO::getColor, Collectors.toList()), + list -> "(" + list.stream().distinct().collect(Collectors.joining(",")) + ")"))); + + // 查看gt 下架的商品有多少相似的货号 + List gtOffSaleBasicList = ObjectUtils.defaultIfNull(redisCache + .getCacheObject(CacheConstants.MIGRATION_GT_OFF_SALE_BASIC_KEY + userId), new ArrayList<>()); + List gtOffSaleArtNoList = gtOffSaleBasicList.stream().map(GtProdSkuVO::getArticle_number).distinct().collect(Collectors.toList()); + + // 找到TY对应的商品 + List tyProdList = ObjectUtils.defaultIfNull(redisCache + .getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + userId), new ArrayList<>()); + 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); + } + })); + + // 清洗后,相同货号映射 + List matchArtNoList = new ArrayList<>(); + List multiMatchGtArtNoList = new ArrayList<>(); + matchArtNoList.add("============ GT和TY匹配的货号 ============"); + // 清洗数据之后,GO平台和TY平台 货号一致的,按照这种来展示: GT => [Z1110(黑色,黑色绒里,棕色,棕色绒里)] <= 清洗后的货号 => [Z1110(黑色,黑色绒里,棕色,棕色绒里)] <= TY + gtMatchTyArtNoMap.forEach((gtArtNo, tyArtNoList) -> { + List tyArtNoColorList = tyArtNoList.stream().map(tyArtNo -> tyArtNo + tyArtNoColorMap.get(tyArtNo)).collect(Collectors.toList()); + final String sameArtNo = "GT => " + gtArtNo + gtOnSaleArtNoColorMap.get(gtArtNo) + " <= " + gtArtNo + " => " + tyArtNoColorList + " <= TY"; + matchArtNoList.add(sameArtNo); + multiMatchGtArtNoList.add(gtArtNo); + }); + + matchArtNoList.add("============ GT独有的货号 ============"); + matchArtNoList.add("============ GT独有的货号 ============"); + // 只存在于GT的货号列表 + gtOnSaleArtNoColorMap.forEach((gtArtNo, gtArtNoColorStr) -> { + if (!multiMatchGtArtNoList.contains(gtArtNo)) { + matchArtNoList.add(gtArtNo + gtArtNoColorStr); + } + }); + + matchArtNoList.add("============ TY独有的货号 ============"); + matchArtNoList.add("============ TY独有的货号 ============"); + List matchTyArtNoList = new ArrayList<>(); + // 共同存在GT 和 TY的TY货号 + gtMatchTyArtNoMap.forEach((gtArtNo, tyArtNoList) -> matchTyArtNoList.addAll(tyArtNoList)); + // 已下架的GT货号,如果能在TY找到匹配的,也要剔除 + gtOffSaleArtNoList.forEach(gtOffSaleArtNo -> tyArtNoColorMap.forEach((tyArtNo, colorNameStr) -> { + if (tyArtNo.contains(gtOffSaleArtNo)) { + matchTyArtNoList.add(tyArtNo); + } + })); + tyArtNoColorMap.forEach((tyArtNo, colorNameStr) -> { + if (!matchTyArtNoList.contains(tyArtNo)) { + matchArtNoList.add(tyArtNo + colorNameStr); + } + }); + + List downloadList = new ArrayList<>(); + for (int i = 0; i < matchArtNoList.size(); i++) { + downloadList.add(new GtAndTYCompareDownloadVO().setOrderNum(i + 1).setCode(matchArtNoList.get(i))); + } + ExcelUtil util = new ExcelUtil<>(GtAndTYCompareDownloadVO.class); + String encodedFileName = URLEncoder.encode("GT与TY差异" + DateUtils.getDate(), "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename=" + encodedFileName + ".xlsx"); + util.exportExcel(response, downloadList, "差异"); + } + + /** + * step2 + * 颜色、客户、商品初始化(包含类目属性及服务等) + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @PostMapping("/init-prod") + @Transactional + public R initProd(@Validated @RequestBody GtAndTYInitVO initVO) { + // 去掉可能的空格 + initVO.setExcludeArtNoList(initVO.getExcludeArtNoList().stream().map(String::trim).collect(Collectors.toList())); + Optional.ofNullable(this.storeMapper.selectOne(new LambdaQueryWrapper() + .eq(Store::getId, initVO.getStoreId()).eq(Store::getDelFlag, Constants.UNDELETED))) + .orElseThrow(() -> new ServiceException("档口不存在!", HttpStatus.ERROR)); + // 步骤1: 颜色初始化 + this.initStoreColorList(initVO.getStoreId(), initVO.getUserId()); + // 步骤2: 客户初始化 + this.initStoreCusList(initVO); + + // 处理的思路,以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 tyProdList = ObjectUtils.defaultIfNull(redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()), new ArrayList<>()); + 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); + } + })); + + // gt按照货号分组 + Map> gtSaleGroupMap = gtOnSaleList.stream().collect(Collectors.groupingBy(GtProdSkuVO::getArticle_number)); + // GT分类 + List cacheList = ObjectUtils.defaultIfNull(redisCache + .getCacheObject(CacheConstants.MIGRATION_GT_SALE_CATE_KEY + initVO.getUserId()), new ArrayList<>()); + List prodCateList = this.prodCateMapper.selectList(new LambdaQueryWrapper() + .eq(SysProductCategory::getDelFlag, Constants.UNDELETED)); + Map dbCateNameMap = prodCateList.stream().collect(Collectors.toMap(SysProductCategory::getName, SysProductCategory::getId)); + // GT商品分类和步橘分类映射 + Map cateRelationMap = new HashMap<>(); + cacheList.forEach(gtCate -> { + final Long cateId = Optional.ofNullable(dbCateNameMap.get(gtCate.getName())).orElseThrow(() -> new ServiceException("GT分类不存在!", HttpStatus.ERROR)); + cateRelationMap.put(gtCate.getId(), cateId); + }); + + // 当天 + final Date voucherDate = java.sql.Date.valueOf(LocalDate.now()); + // 所有商品的类目属性map key gt的product_id value StoreProductCategoryAttribute + Map prodAttrMap = new HashMap<>(); + // 待导入的商品 + List storeProdList = new ArrayList<>(); + gtMatchTyArtNoMap.forEach((gtArtNo, tyArtNoList) -> { + // 排除掉需要特殊处理的货号 + if (CollectionUtils.isEmpty(initVO.getExcludeArtNoList()) || !initVO.getExcludeArtNoList().contains(gtArtNo)) { + // 获取GT匹配的商品中的第一个商品 + List gtMatchSkuList = gtSaleGroupMap.get(gtArtNo); + // 初始化档口商品 + StoreProduct storeProd = new StoreProduct().setStoreId(initVO.getStoreId()).setProdCateId(cateRelationMap.get(gtMatchSkuList.get(0).getCategory_nid())) + .setPrivateItem(0).setProdArtNum(gtMatchSkuList.get(0).getArticle_number()).setProdTitle(gtMatchSkuList.get(0).getCharacters()).setListingWay(ListingType.RIGHT_NOW.getValue()) + .setVoucherDate(voucherDate).setProdStatus(EProductStatus.ON_SALE.getValue()).setRecommendWeight(0L).setSaleWeight(0L).setPopularityWeight(0L); + // 提前设置档口商品的类目属性 + this.preMatchAttr(gtMatchSkuList.get(0).getProduct_id(), initVO.getUserId(), prodAttrMap); + storeProdList.add(storeProd); + } + }); + this.storeProdMapper.insert(storeProdList); + + // 步骤4: 初始化商品属性 + List prodSvcList = new ArrayList<>(); + List prodAttrList = new ArrayList<>(); + storeProdList.forEach(storeProd -> { + // 获取GT匹配的商品sku列表 + List gtMatchSkuList = gtSaleGroupMap.get(storeProd.getProdArtNum()); + // 初始化商品服务承诺 + prodSvcList.add(new StoreProductService().setStoreProdId(storeProd.getId()).setCustomRefund("0") + .setThirtyDayRefund("0").setOneBatchSale("1").setRefundWithinThreeDay("0")); + // 初始化商品的类目属性 + StoreProductCategoryAttribute cateAttr = Optional.ofNullable(prodAttrMap.get(gtMatchSkuList.get(0).getProduct_id())).orElse(new StoreProductCategoryAttribute()); + cateAttr.setStoreId(storeProd.getStoreId()).setStoreProdId(storeProd.getId()); + prodAttrList.add(cateAttr); + }); + // 插入商品颜色及颜色对应的尺码,档口服务承诺 + this.prodSvcMapper.insert(prodSvcList); + this.prodCateAttrMapper.insert(prodAttrList); + return R.ok(); + } + + + /** + * step3 + * 商品颜色及商品颜色尺码 + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @PostMapping("/init-color") + @Transactional + public R initColor(@Validated @RequestBody GtAndTYInitVO initVO) { + // 从数据库查询最新数据 + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getStoreId, initVO.getStoreId()).eq(StoreProduct::getDelFlag, Constants.UNDELETED)); + List storeColorList = this.storeColorMapper.selectList(new LambdaQueryWrapper() + .eq(StoreColor::getStoreId, initVO.getStoreId()).eq(StoreColor::getDelFlag, Constants.UNDELETED)); + Map storeColorMap = storeColorList.stream().collect(Collectors.toMap(StoreColor::getColorName, x -> x)); + + // 处理的思路,以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()); + // gt按照货号分组 + Map> gtSaleGroupMap = gtOnSaleList.stream().collect(Collectors.groupingBy(GtProdSkuVO::getArticle_number)); + + // 找到TY对应的商品 + List tyProdList = ObjectUtils.defaultIfNull(redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()), new ArrayList<>()); + // TY货号下颜色的map + Map> tyProdGroupMap = tyProdList.stream().collect(Collectors.groupingBy(TyProdImportVO::getProdArtNum)); + 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); + } + })); + + // 商品所有颜色 尺码 颜色库存初始化 + List prodColorList = new ArrayList<>(); + List prodColorSizeList = new ArrayList<>(); + storeProdList.forEach(storeProd -> { + // TY匹配的货号 + List tyMatchArtNoList = gtMatchTyArtNoMap.get(storeProd.getProdArtNum()); + // 获取GT匹配的商品sku列表 + List gtMatchSkuList = gtSaleGroupMap.get(storeProd.getProdArtNum()); + // 当前货号在GT的所有尺码,作为标准尺码 + List gtStandardSizeList = gtMatchSkuList.stream().map(sku -> (int) Math.floor(Double.parseDouble(sku.getSize()))).collect(Collectors.toList()); + AtomicInteger orderNum = new AtomicInteger(); + tyMatchArtNoList.forEach(tyArtNo -> { + List tyMatchSkuList = tyProdGroupMap.get(tyArtNo); + for (TyProdImportVO tyProdImportVO : tyMatchSkuList) { + StoreColor storeColor = Optional.ofNullable(storeColorMap.get(tyProdImportVO.getColorName())) + .orElseThrow(() -> new ServiceException("没有TY商品颜色!" + tyArtNo, HttpStatus.ERROR)); + // 该商品的颜色 + prodColorList.add(new StoreProductColor().setStoreId(storeProd.getStoreId()).setStoreProdId(storeProd.getId()).setOrderNum(orderNum.addAndGet(1)) + .setColorName(storeColor.getColorName()).setStoreColorId(storeColor.getId()).setProdStatus(EProductStatus.ON_SALE.getValue())); + // 该颜色所有的尺码 + for (int j = 0; j < Constants.SIZE_LIST.size(); j++) { + // TY系统条码前缀 + final String otherSnPrefix = tyProdImportVO.getTySnPrefix() + Constants.SIZE_LIST.get(j); + prodColorSizeList.add(new StoreProductColorSize().setSize(Constants.SIZE_LIST.get(j)).setStoreColorId(storeColor.getId()) + .setStoreProdId(storeProd.getId()).setPrice(tyProdImportVO.getPrice()).setOtherSnPrefix(otherSnPrefix).setNextSn(0) + .setStandard(gtStandardSizeList.contains(Constants.SIZE_LIST.get(j)) ? 1 : 0)); + } + } + }); + }); + // 插入商品颜色及颜色对应的尺码,档口服务承诺 + this.prodColorMapper.insert(prodColorList); + prodColorSizeList.sort(Comparator.comparing(StoreProductColorSize::getStoreProdId).thenComparing(StoreProductColorSize::getSize)); + this.prodColorSizeMapper.insert(prodColorSizeList); + // 还要更新步橘系统的条码前缀 + prodColorSizeList.forEach(x -> x.setSnPrefix(initVO.getStoreId() + String.format("%08d", x.getId()))); + this.prodColorSizeMapper.updateById(prodColorSizeList); + return R.ok(); + } + + + + + + + + + + + /** + * step4 + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @PostMapping("/init-cus-disc") + @Transactional + public R initCusDisc(@Validated @RequestBody GtAndTYInitVO initVO) { + + List storeProdList = this.storeProdMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProduct::getStoreId, initVO.getStoreId()).eq(StoreProduct::getDelFlag, Constants.UNDELETED)); + List prodColorList = this.prodColorMapper.selectList(new LambdaQueryWrapper() + .eq(StoreProductColor::getStoreId, initVO.getStoreId()).eq(StoreProductColor::getDelFlag, Constants.UNDELETED)); + 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); + } + }); + + // TY商品缓存 + List cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()); + if (CollectionUtils.isEmpty(cacheList)) { + throw new ServiceException("TY商品列表为空", HttpStatus.ERROR); + } + // ty货号正在生效的颜色map,因为客户优惠有些是删除的颜色,需要通过这里去过滤 + Map> tyExistArtNoColorMap = cacheList.stream().collect(Collectors + .groupingBy(TyProdImportVO::getProdArtNum, Collectors.mapping(TyProdImportVO::getColorName, Collectors.toSet()))); + // 从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); + } + // 从redis中获取已存在的商品库存数据 + List tyStockList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_STOCK_KEY + initVO.getUserId()); + if (CollectionUtils.isEmpty(tyStockList)) { + throw new ServiceException("ty供应商商品库存列表为空!" + initVO.getUserId(), HttpStatus.ERROR); + } + // TY 货号颜色的库存对应关系 + Map> tyProdStockMap = tyStockList.stream().collect(Collectors + .groupingBy(TyProdStockVO::getProdArtNum, Collectors.toMap(TyProdStockVO::getColorName, x -> x))); + // TY 货号颜色优惠对应关系 + Map>> tyCusDiscGroupMap = tyCusDiscCacheList.stream().collect(Collectors + .groupingBy(TyCusDiscImportVO::getProdArtNum, Collectors.groupingBy(TyCusDiscImportVO::getColorName))); + // 步橘系统商品所有颜色maps + Map> prodColorGroupMap = prodColorList.stream().collect(Collectors + .groupingBy(StoreProductColor::getStoreProdId, Collectors.toMap(StoreProductColor::getColorName, x -> x))); + // 步橘系统客户名称map + Map buJuStoreCusMap = storeCusList.stream().collect(Collectors.toMap(StoreCustomer::getCusName, x -> x)); + List prodCusDiscList = new ArrayList<>(); + 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)); + // 处理档口商品库存 + this.handleProdStock(tyAtrNoList, tyProdStockMap, buJuProdColorMap, storeProd.getStoreId(), storeProd.getId(), storeProd.getProdArtNum(), prodStockList); + + + tyAtrNoList.forEach(tyAtrNo -> { + // 处理客户优惠 + this.handleCusDisc(tyAtrNo, tyExistArtNoColorMap, tyCusDiscGroupMap, buJuProdColorMap, buJuStoreCusMap, prodCusDiscList, storeProd.getStoreId(), storeProd.getId()); + }); + + + }); + // 档口客户优惠 + this.storeCusProdDiscMapper.insert(prodCusDiscList); + // 档口客户库存 + this.prodStockMapper.insert(prodStockList); + return R.ok(); + } + + + /** + * 初始化系统颜色 + * + * @param storeId 档口ID + * @param userId GT用户ID + */ + private void initStoreColorList(Long storeId, Integer userId) { + // TY商品缓存 + List cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + userId); + if (CollectionUtils.isEmpty(cacheList)) { + throw new ServiceException("TY商品列表为空", HttpStatus.ERROR); + } + List tyColorList = cacheList.stream().map(TyProdImportVO::getColorName).distinct().collect(Collectors.toList()); + List storeColorList = new ArrayList<>(); + for (int i = 0; i < tyColorList.size(); i++) { + storeColorList.add(new StoreColor().setStoreId(storeId).setColorName(tyColorList.get(i)).setOrderNum(i + 1)); + } + this.storeColorMapper.insert(storeColorList); + storeColorList.stream().collect(Collectors.toMap(StoreColor::getColorName, x -> x)); + } + + /** + * 处理商品库存 + */ + private void handleProdStock(List tyAtrNoList, Map> tyProdStockMap, Map buJuProdColorMap, + Long storeId, Long storeProdId, String prodArtNum, List prodStockList) { + // 获取ty货号所有颜色的库存 + Map tyColorStockMap = new HashMap<>(); + tyAtrNoList.forEach(tyArtNo -> tyColorStockMap.putAll(tyProdStockMap.getOrDefault(tyArtNo, new HashMap<>()))); + buJuProdColorMap.forEach((buJuColor, buJuProdColor) -> { + StoreProductStock stock = new StoreProductStock().setStoreId(storeId).setStoreProdId(storeProdId).setProdArtNum(prodArtNum) + .setColorName(buJuProdColorMap.get(buJuColor).getColorName()).setStoreProdColorId(buJuProdColorMap.get(buJuColor).getId()) + .setStoreColorId(buJuProdColorMap.get(buJuColor).getStoreColorId()); + if (tyColorStockMap.containsKey(buJuColor)) { + TyProdStockVO tySizeStock = tyColorStockMap.getOrDefault(buJuColor, null); + stock.setSize30(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize30() : null) + .setSize31(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize31() : null) + .setSize32(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize32() : null) + .setSize33(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize33() : null) + .setSize34(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize34() : null) + .setSize35(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize35() : null) + .setSize36(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize36() : null) + .setSize37(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize37() : null) + .setSize38(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize38() : null) + .setSize39(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize39() : null) + .setSize40(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize40() : null) + .setSize41(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize41() : null) + .setSize42(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize42() : null) + .setSize43(ObjectUtils.isNotEmpty(tySizeStock) ? tySizeStock.getSize43() : null); + } + prodStockList.add(stock); + }); + } + + /** + * 处理档口客户优惠 + */ + private void handleCusDisc(String tyAtrNo, Map> tyExistArtNoColorMap, + Map>> tyCusDiscGroupMap, + Map buJuProdColorMap, Map buJuStoreCusMap, + List prodCusDiscList, Long storeId, Long storeProdId) { + // TY货号下有哪些颜色存在客户优惠 + Map> tyColorCusDiscMap = tyCusDiscGroupMap.get(tyAtrNo); + if (MapUtils.isEmpty(tyColorCusDiscMap)) { + return; + } + // ty当前货号正在生效的颜色列表 + Set existColorSet = tyExistArtNoColorMap.getOrDefault(tyAtrNo, Collections.emptySet()); + // 依次遍历存在优惠的颜色,设置步橘系统客户优惠关系 + tyColorCusDiscMap.forEach((tyColor, tyCusDiscList) -> { + // 必须是现在正在生效的颜色,才会被添加到系统中 + if (!existColorSet.contains(tyColor)) { + return; + } + // TODO 该处TY 与 FHB处理不同 + // TODO 该处TY 与 FHB处理不同 + // TODO 该处TY 与 FHB处理不同 + tyCusDiscList.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客户优惠 转为步橘系统优惠 + prodCusDiscList.add(new StoreCustomerProductDiscount().setStoreId(storeId).setStoreProdId(storeProdId).setStoreCusId(storeCus.getId()) + .setStoreCusName(storeCus.getCusName()).setStoreProdColorId(buJuProdColor.getId()).setDiscount(tyCusDisc.getDiscount())); + }); + }); + } + + /** + * 初始化客户列表 + * + * @param initVO 入参 + * @return List + */ + private List initStoreCusList(GtAndTYInitVO initVO) { + List cacheList = ObjectUtils.defaultIfNull(redisCache + .getCacheObject(CacheConstants.MIGRATION_TY_CUS_KEY + initVO.getUserId()), new ArrayList<>()); + if (CollectionUtils.isEmpty(cacheList)) { + throw new ServiceException("供应商客户列表为空!", HttpStatus.ERROR); + } + List storeCusList = cacheList.stream() + // 排除掉现金客户 因为档口入驻时,会自动创建现金客户 + .filter(x -> !Objects.equals(x.getCusName(), Constants.STORE_CUS_CASH)) + .map(x -> new StoreCustomer().setStoreId(initVO.getStoreId()).setCusName(x.getCusName())) + .collect(Collectors.toList()); + this.storeCusMapper.insert(storeCusList); + return storeCusList; + } + + /** + * 提前匹配类目属性 + * + * @param product_id GT商品ID + * @param userId GT用户ID + * @param prodAttrMap 类目属性 + */ + private void preMatchAttr(Integer product_id, Integer userId, Map prodAttrMap) { + // 类目属性 + Map attrMap = redisCache.getCacheMap(CacheConstants.MIGRATION_GT_SALE_ATTR_KEY + userId + "_" + product_id); + if (MapUtils.isEmpty(attrMap)) { + return; + } + // 将attrMap 的 key 映射到系统中 + StoreProductCategoryAttribute prodAttr = new StoreProductCategoryAttribute(); + // 1. 帮面材质 + if (attrMap.containsKey(Constants.UPPER_MATERIAL_NAME)) { + prodAttr.setUpperMaterial(attrMap.get(Constants.UPPER_MATERIAL_NAME)); + } + // 2. 靴筒内里材质 + if (attrMap.containsKey(Constants.SHAFT_LINING_MATERIAL_NAME)) { + prodAttr.setShaftLiningMaterial(attrMap.get(Constants.SHAFT_LINING_MATERIAL_NAME)); + } + // 3. 靴筒面材质 + if (attrMap.containsKey(Constants.SHAFT_MATERIAL_NAME)) { + prodAttr.setShaftMaterial(attrMap.get(Constants.SHAFT_MATERIAL_NAME)); + } + // 4. 鞋面内里材质 + if (attrMap.containsKey(Constants.SHOE_UPPER_LINING_MATERIAL_NAME)) { + prodAttr.setShoeUpperLiningMaterial(attrMap.get(Constants.SHOE_UPPER_LINING_MATERIAL_NAME)); + } + // 5. 靴款品名 + if (attrMap.containsKey(Constants.SHOE_STYLE_NAME_NAME)) { + prodAttr.setShoeStyleName(attrMap.get(Constants.SHOE_STYLE_NAME_NAME)); + } + // 6. 筒高 + if (attrMap.containsKey(Constants.SHAFT_HEIGHT_NAME)) { + prodAttr.setShaftHeight(attrMap.get(Constants.SHAFT_HEIGHT_NAME)); + } + // 7. 鞋垫材质 + if (attrMap.containsKey(Constants.INSOLE_MATERIAL_NAME)) { + prodAttr.setInsoleMaterial(attrMap.get(Constants.INSOLE_MATERIAL_NAME)); + } + // 8. 上市年份季节 + if (attrMap.containsKey(Constants.RELEASE_YEAR_SEASON_NAME)) { + prodAttr.setReleaseYearSeason(attrMap.get(Constants.RELEASE_YEAR_SEASON_NAME)); + } + // 9. 后跟高 + if (attrMap.containsKey(Constants.HEEL_HEIGHT_NAME)) { + prodAttr.setHeelHeight(attrMap.get(Constants.HEEL_HEIGHT_NAME)); + } + // 10. 跟底款式 + if (attrMap.containsKey(Constants.HEEL_TYPE_NAME)) { + prodAttr.setHeelType(attrMap.get(Constants.HEEL_TYPE_NAME)); + } + // 11. 鞋头款式 + if (attrMap.containsKey(Constants.TOE_STYLE_NAME)) { + prodAttr.setToeStyle(attrMap.get(Constants.TOE_STYLE_NAME)); + } + // 12. 适合季节 + if (attrMap.containsKey(Constants.SUITABLE_SEASON_NAME)) { + prodAttr.setSuitableSeason(attrMap.get(Constants.SUITABLE_SEASON_NAME)); + } + // 13. 开口深度 + if (attrMap.containsKey(Constants.COLLAR_DEPTH_NAME)) { + prodAttr.setCollarDepth(attrMap.get(Constants.COLLAR_DEPTH_NAME)); + } + // 14. 鞋底材质 + if (attrMap.containsKey(Constants.OUTSOLE_MATERIAL_NAME)) { + prodAttr.setOutsoleMaterial(attrMap.get(Constants.OUTSOLE_MATERIAL_NAME)); + } + // 15. 风格 + if (attrMap.containsKey(Constants.STYLE_NAME)) { + prodAttr.setStyle(attrMap.get(Constants.STYLE_NAME)); + } + // 16. 款式 + if (attrMap.containsKey(Constants.DESIGN_NAME)) { + prodAttr.setDesign(attrMap.get(Constants.DESIGN_NAME)); + } + // 17. 皮质特征 + if (attrMap.containsKey(Constants.LEATHER_FEATURES_NAME)) { + prodAttr.setLeatherFeatures(attrMap.get(Constants.LEATHER_FEATURES_NAME)); + } + // 18. 制作工艺 + if (attrMap.containsKey(Constants.MANUFACTURING_PROCESS_NAME)) { + prodAttr.setManufacturingProcess(attrMap.get(Constants.MANUFACTURING_PROCESS_NAME)); + } + // 19. 图案 + if (attrMap.containsKey(Constants.PATTERN_NAME)) { + prodAttr.setPattern(attrMap.get(Constants.PATTERN_NAME)); + } + // 20. 闭合方式 + if (attrMap.containsKey(Constants.CLOSURE_TYPE_NAME)) { + prodAttr.setClosureType(attrMap.get(Constants.CLOSURE_TYPE_NAME)); + } + // 21. 适用场景 + if (attrMap.containsKey(Constants.OCCASION_NAME)) { + prodAttr.setOccasion(attrMap.get(Constants.OCCASION_NAME)); + } + // 22. 厚薄 + if (attrMap.containsKey(Constants.THICKNESS_NAME)) { + prodAttr.setThickness(attrMap.get(Constants.THICKNESS_NAME)); + } + // 23. 流行元素 + if (attrMap.containsKey(Constants.FASHION_ELEMENTS_NAME)) { + prodAttr.setFashionElements(attrMap.get(Constants.FASHION_ELEMENTS_NAME)); + } + // 24. 适用对象 + if (attrMap.containsKey(Constants.SUITABLE_PERSON_NAME)) { + prodAttr.setSuitablePerson(attrMap.get(Constants.SUITABLE_PERSON_NAME)); + } + 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 7341d4f4a..842df6c1d 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 @@ -106,7 +106,7 @@ public class GtAndTyBizController extends BaseController { .getCacheObject(CacheConstants.MIGRATION_GT_SALE_BASIC_KEY + userId), new ArrayList<>()); Map articleNoColorMap = gtSaleBasicList.stream().collect(Collectors.groupingBy(GtProdSkuVO::getArticle_number, Collectors.collectingAndThen(Collectors.mapping(GtProdSkuVO::getColor, Collectors.toList()), - list -> "(" + String.join(",", list) + ")"))); + list -> "(" + list.stream().distinct().collect(Collectors.joining(",")) + ")"))); List doubleRunSaleArtNoList = gtSaleBasicList.stream().map(GtProdSkuVO::getArticle_number).distinct().collect(Collectors.toList()); // 查看double_run 在售的商品 这边有多少相似的货号 doubleRunSaleArtNoList.forEach(article_number -> { @@ -134,7 +134,7 @@ public class GtAndTyBizController extends BaseController { .getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + userId), new ArrayList<>()); Map tyProdArtNumColorMap = tyProdList.stream().collect(Collectors.groupingBy(TyProdImportVO::getProdArtNum, Collectors.collectingAndThen(Collectors.mapping(TyProdImportVO::getColorName, Collectors.toList()), - list -> "(" + String.join(",", list) + ")"))); + list -> "(" + list.stream().distinct().collect(Collectors.joining(",")) + ")"))); List tyArtNoList = tyProdList.stream().map(TyProdImportVO::getProdArtNum).distinct().collect(Collectors.toList()); tyArtNoList.forEach(prodArtNum -> { // 只保留核心连续的数字,去除其他所有符号 @@ -281,9 +281,11 @@ public class GtAndTyBizController extends BaseController { // 获取GT匹配的商品中的第一个商品 List gtMatchSkuList = this.getGtFirstSku(multiSaleSameGoMap, gtSaleGroupMap, cleanArtNo); // 初始化档口商品 - StoreProduct storeProd = new StoreProduct().setStoreId(initVO.getStoreId()).setProdCateId(cateRelationMap.get(gtMatchSkuList.get(0).getCategory_nid())) - .setProdArtNum(gtMatchSkuList.get(0).getArticle_number()).setProdTitle(gtMatchSkuList.get(0).getCharacters()).setListingWay(ListingType.RIGHT_NOW.getValue()) - .setVoucherDate(voucherDate).setProdStatus(EProductStatus.ON_SALE.getValue()).setRecommendWeight(0L).setSaleWeight(0L).setPopularityWeight(0L); + StoreProduct storeProd = new StoreProduct().setStoreId(initVO.getStoreId()) + .setProdCateId(cateRelationMap.get(gtMatchSkuList.get(0).getCategory_nid())).setPrivateItem(0) + .setProdArtNum(gtMatchSkuList.get(0).getArticle_number()).setProdTitle(gtMatchSkuList.get(0).getCharacters()) + .setListingWay(ListingType.RIGHT_NOW.getValue()).setVoucherDate(voucherDate).setProdStatus(EProductStatus.ON_SALE.getValue()) + .setRecommendWeight(0L).setSaleWeight(0L).setPopularityWeight(0L); // 提前设置档口商品的类目属性 this.preMatchAttr(gtMatchSkuList.get(0).getProduct_id(), initVO.getUserId(), prodAttrMap); storeProdList.add(storeProd); @@ -302,8 +304,7 @@ public class GtAndTyBizController extends BaseController { prodSvcList.add(new StoreProductService().setStoreProdId(storeProd.getId()).setCustomRefund("0") .setThirtyDayRefund("0").setOneBatchSale("1").setRefundWithinThreeDay("0")); // 初始化商品的类目属性 - StoreProductCategoryAttribute cateAttr = Optional.ofNullable(prodAttrMap.get(gtMatchSkuList.get(0).getProduct_id())) - .orElseThrow(() -> new ServiceException("没有GT商品类目属性!" + storeProd.getProdArtNum(), HttpStatus.ERROR)); + StoreProductCategoryAttribute cateAttr = Optional.ofNullable(prodAttrMap.get(gtMatchSkuList.get(0).getProduct_id())).orElse(new StoreProductCategoryAttribute()); cateAttr.setStoreId(storeProd.getStoreId()).setStoreProdId(storeProd.getId()); prodAttrList.add(cateAttr); }); @@ -330,7 +331,6 @@ public class GtAndTyBizController extends BaseController { Map storeColorMap = storeColorList.stream().collect(Collectors.toMap(StoreColor::getColorName, x -> x)); Map> multiSaleSameGoMap = new HashMap<>(); - Map> multiOffSaleSameGoMap = new HashMap<>(); Map> multiSameTyMap = new HashMap<>(); List gtSaleBasicList = ObjectUtils.defaultIfNull(redisCache .getCacheObject(CacheConstants.MIGRATION_GT_SALE_BASIC_KEY + initVO.getUserId()), new ArrayList<>()); @@ -346,17 +346,6 @@ public class GtAndTyBizController extends BaseController { } }); - // 查看gt 下架的商品有多少相似的货号 - List gtOffSaleBasicList = ObjectUtils.defaultIfNull(redisCache - .getCacheObject(CacheConstants.MIGRATION_GT_OFF_SALE_BASIC_KEY + initVO.getUserId()), new ArrayList<>()); - gtOffSaleBasicList.stream().map(GtProdSkuVO::getArticle_number).distinct().forEach(article_number -> { - // 只保留核心连续的数字,去除其他所有符号 - String cleanArtNo = this.extractCoreArticleNumber(article_number); - List existList = multiOffSaleSameGoMap.containsKey(cleanArtNo) ? multiOffSaleSameGoMap.get(cleanArtNo) : new ArrayList<>(); - existList.add(article_number); - multiOffSaleSameGoMap.put(cleanArtNo, existList); - }); - // 查看TY 这边有多少相似的货号 List tyProdList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_PROD_KEY + initVO.getUserId()); // TY按照颜色分类 @@ -458,6 +447,9 @@ public class GtAndTyBizController extends BaseController { 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)) { @@ -580,6 +572,7 @@ public class GtAndTyBizController extends BaseController { } // TODO 该处TY 与 FHB处理不同 // TODO 该处TY 与 FHB处理不同 + // TODO 该处TY 与 FHB处理不同 tyCusDiscList.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)); 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 8d1cd1577..82ea46316 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 @@ -8,6 +8,7 @@ import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.web.controller.xkt.migartion.vo.CusDiscErrorVO; import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyCusDiscImportVO; import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyCusImportVO; import com.ruoyi.web.controller.xkt.migartion.vo.ty.TyProdImportVO; @@ -20,12 +21,8 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -94,47 +91,18 @@ public class TyController extends BaseController { */ @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") @PostMapping("/cus/disc/cache") - public R createCusDiscCache(@RequestParam(value = "userId") Long userId, @RequestParam(value = "cusName") String cusName, - @RequestParam(value = "selfCheck") Boolean selfCheck, MultipartFile file) throws IOException { - // 判断客户是否存在 - List tyCusVOList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_KEY + userId); - Map tyCusMap = tyCusVOList.stream().collect(Collectors.toMap(TyCusImportVO::getCusName, x -> x)); - if (!tyCusMap.containsKey(cusName)) { - throw new ServiceException(cusName + " : 客户不存在", HttpStatus.ERROR); - } + public R createCusDiscCache(@RequestParam(value = "userId") Long userId, + @RequestParam(value = "cusName") String cusName, MultipartFile file) throws IOException { + ExcelUtil util = new ExcelUtil<>(TyCusDiscImportVO.class); + List tyProdVOList = util.importExcel(file.getInputStream()); // 从redis中获取已存在的客户优惠数据 List cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_DISCOUNT_KEY + userId); cacheList = Optional.ofNullable(cacheList).orElse(new ArrayList<>()); - // 判断当前客户是否已导入过,若是则直接报错 - Map> cusDiscMap = cacheList.stream().collect(Collectors.groupingBy(TyCusDiscImportVO::getCusName)); - if (cusDiscMap.containsKey(cusName)) { - throw new ServiceException(cusName + " : 客户已导入过优惠数据", HttpStatus.ERROR); - } - ExcelUtil util = new ExcelUtil<>(TyCusDiscImportVO.class); - List tyProdVOList = util.importExcel(file.getInputStream()); - // 是否要自校验,校验识图是否准确 - if (selfCheck) { - Map> artNoColorDiscountMap = tyProdVOList.stream() - // 只设置有优惠的存货及颜色 - .filter(x -> ObjectUtils.isNotEmpty(x.getBasicPrice())) - .collect(Collectors.groupingBy(TyCusDiscImportVO::getProdArtNum, Collectors.toMap(TyCusDiscImportVO::getColorName, x -> - ObjectUtils.defaultIfNull(x.getBasicPrice(), 0) - ObjectUtils.defaultIfNull(x.getCustomerPrice(), 0), (v1, v2) -> v2))); - // 校验同一客户在同一货号不同颜色存在优惠是否相同,不同则需要提示 - List discErrorList = new ArrayList<>(); - artNoColorDiscountMap.forEach((artNo, colorDiscMap) -> { - // 判断colorDiscMap所有颜色的优惠是否相同 - if (colorDiscMap.values().stream().distinct().count() > 1) { - discErrorList.add(cusName + ":" + artNo + "," + "不同颜色优惠力度不同!"); - } - }); - if (CollectionUtils.isNotEmpty(discErrorList)) { - throw new ServiceException(discErrorList.toString(), HttpStatus.ERROR); - } - } + // 前置校验 + this.cusDiscPrefixFilter(userId, cusName, cacheList); // 因为是采用的截图转excel方式,所以每个张图会冗余部分数据长度,导入是需要判断是否已存在 - Map importCusDiscMap = new ConcurrentHashMap<>(); + Map importCusDiscMap = new HashMap<>(); List importList = new ArrayList<>(); - List errorList = new ArrayList<>(); tyProdVOList.stream() // 只设置有优惠的存货及颜色 .filter(x -> ObjectUtils.isNotEmpty(x.getBasicPrice()) && ObjectUtils.isNotEmpty(x.getCustomerPrice())) @@ -142,10 +110,7 @@ public class TyController extends BaseController { if (importCusDiscMap.containsKey(x.getProdArtNum() + ":" + x.getColorName())) { System.err.println(x.getProdArtNum() + ":" + x.getColorName()); } else { - final int discount = x.getBasicPrice() - x.getCustomerPrice(); - if (discount <= 0) { - errorList.add(cusName + ":" + x.getProdArtNum() + ":" + x.getColorName() + ":优惠金额不能小于等于0"); - } + final int discount = ObjectUtils.defaultIfNull(x.getBasicPrice(), 0) - ObjectUtils.defaultIfNull(x.getCustomerPrice(), 0); String prodArtNum = x.getProdArtNum().trim(); String colorName = x.getColorName().trim(); // 如果货号包括-R 则表明是 货号为绒里,手动给颜色添加后缀“绒里” @@ -157,16 +122,15 @@ public class TyController extends BaseController { importList.add(x); } }); - if (CollectionUtils.isNotEmpty(errorList)) { - throw new ServiceException(errorList.toString(), HttpStatus.ERROR); - } // 加到总的客户优惠上 CollectionUtils.addAll(cacheList, importList); + // TODO 过滤优惠大于0 是在比较插入数据的时候做的 // 存到redis中 redisCache.setCacheObject(CacheConstants.MIGRATION_TY_CUS_DISCOUNT_KEY + userId, cacheList); return R.ok(); } + /** * step4 */ @@ -175,6 +139,22 @@ public class TyController extends BaseController { public R createTyProdStockCache(@PathVariable Integer userId, MultipartFile file) throws IOException { ExcelUtil util = new ExcelUtil<>(TyProdStockVO.class); List tyStockList = util.importExcel(file.getInputStream()); + + /*// 判断货号 + 颜色是否存在,“图识”可能不准 + 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)); + // 错误的货号和颜色,“图识”不准的部分 + List errorList = new ArrayList<>(); + tyStockList.forEach(x -> { + if (!tyProdColorMap.containsKey(x.getProdArtNum() + ":" + x.getColorName())) { + errorList.add(x.getProdArtNum() + ":" + x.getColorName() + ":货号 + 颜色不存在"); + } + }); + if (CollectionUtils.isNotEmpty(errorList)) { + throw new ServiceException(errorList.toString(), HttpStatus.ERROR); + }*/ + // 因为是采用的截图转excel方式,所以每个张图会冗余部分数据长度,导入是需要判断是否已存在 Map importStockMap = new ConcurrentHashMap<>(); List cacheList = new ArrayList<>(); @@ -196,5 +176,78 @@ public class TyController extends BaseController { return R.ok(); } + /** + * step5 + */ + @PreAuthorize("@ss.hasAnyRoles('admin,general_admin')") + @GetMapping("/error/cus/disc/{userId}") + public R getErrorCusDisc(@PathVariable Integer userId){ + List cacheList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_DISCOUNT_KEY + userId); + List errDiscList = new ArrayList<>(); + // 1. 有哪些是优惠价大于销售价的 + cacheList.forEach(record -> { + final Integer basicPrice = ObjectUtils.defaultIfNull(record.getBasicPrice(), 0); + final Integer customerPrice = ObjectUtils.defaultIfNull(record.getCustomerPrice(), 0); + if (basicPrice - customerPrice <= 0) { + errDiscList.add(record.getProdArtNum() + ":" + record.getCusName() + ":" + record.getColorName() + ",优惠价大于等于原售价"); + } + }); + // 2. 有哪些优惠是同一货号不同颜色优惠金额不一致 + List errCusDiscUnSameList = new ArrayList<>(); + Map>> artNoCusDiscMap = cacheList.stream().collect(Collectors + .groupingBy(TyCusDiscImportVO::getProdArtNum, Collectors.groupingBy(TyCusDiscImportVO::getCusName))); + // 货号下客户优惠的map + artNoCusDiscMap.forEach((artNo, cusDiscMap) -> cusDiscMap.forEach((cusName, cusDiscList) -> { + // 不同颜色优惠的map + Map colorDiscMap = cusDiscList.stream().collect(Collectors + .toMap(TyCusDiscImportVO::getColorName, x -> ObjectUtils.defaultIfNull(x.getDiscount(), 0))); + // 判断所有颜色的优惠金额是否一致 + Set discValueSet = new HashSet<>(colorDiscMap.values()); + if (discValueSet.size() > 1) { + errCusDiscUnSameList.add(artNo + ":" + cusName + ":" + colorDiscMap.keySet() + ",优惠金额不一致"); + } + })); + return R.ok(new CusDiscErrorVO().setErrCusDiscUnSameList(errCusDiscUnSameList).setErrDiscList(errDiscList)); + } + + + /** + * 客户优惠前置校验 + */ + private void cusDiscPrefixFilter(Long userId, String cusName, List cacheList) { + // 判断客户是否存在 + List tyCusVOList = redisCache.getCacheObject(CacheConstants.MIGRATION_TY_CUS_KEY + userId); + Map tyCusMap = tyCusVOList.stream().collect(Collectors.toMap(TyCusImportVO::getCusName, x -> x)); + if (!tyCusMap.containsKey(cusName)) { + throw new ServiceException(cusName + " : 客户不存在", HttpStatus.ERROR); + } + // 判断当前客户是否已导入过,若是则直接报错 + Map> cusDiscMap = cacheList.stream().collect(Collectors.groupingBy(TyCusDiscImportVO::getCusName)); + 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)); + // 错误的货号和颜色,“图识”不准的部分 + List errorList = new ArrayList<>(); + cacheList.forEach(x -> { + if (!tyProdColorMap.containsKey(x.getProdArtNum() + ":" + x.getColorName())) { + errorList.add(cusName + ":" + x.getProdArtNum() + ":" + x.getColorName() + ":货号 + 颜色不存在"); + } + }); + if (CollectionUtils.isNotEmpty(errorList)) { + throw new ServiceException(errorList.toString(), HttpStatus.ERROR); + }*/ + + + + + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/vo/CusDiscErrorVO.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/vo/CusDiscErrorVO.java new file mode 100644 index 000000000..d2f1370f0 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/xkt/migartion/vo/CusDiscErrorVO.java @@ -0,0 +1,21 @@ +package com.ruoyi.web.controller.xkt.migartion.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +/** + * @author liangyq + * @date 2025-05-11 23:46 + */ +@Data +@Accessors(chain = true) +public class CusDiscErrorVO { + + // 客户优惠金额小于0 + private List errDiscList; + // 客户在同一货品,不同颜色优惠金额不一致 + private List errCusDiscUnSameList; + +}