|
@@ -40,9 +40,13 @@ import zs.payment.service.flymall.b2cgoodsskuinonline.B2cGoodsSkuInOnlineService
|
|
|
import zs.payment.service.flymall.b2cgoodsspuinonline.B2cGoodsSpuInOnlineService;
|
|
import zs.payment.service.flymall.b2cgoodsspuinonline.B2cGoodsSpuInOnlineService;
|
|
|
import zs.payment.service.flymall.b2cshop.B2cShopService;
|
|
import zs.payment.service.flymall.b2cshop.B2cShopService;
|
|
|
|
|
|
|
|
|
|
+import zs.payment.mapper.flymall.B2cGoodsAttrMapper;
|
|
|
|
|
+import zs.payment.mapper.flymall.B2cGoodsSpuInOnlineMapper;
|
|
|
import zs.payment.messages.KafkaProducer;
|
|
import zs.payment.messages.KafkaProducer;
|
|
|
|
|
+import zs.payment.utils.RedisUtils;
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigDecimal;
|
|
|
|
|
+import java.sql.Timestamp;
|
|
|
import java.math.RoundingMode;
|
|
import java.math.RoundingMode;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
@@ -85,6 +89,12 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private KafkaProducer kafkaProducer;
|
|
private KafkaProducer kafkaProducer;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private RedisUtils redisUtils;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private B2cGoodsSpuInOnlineMapper b2cGoodsSpuInOnlineMapper;
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private B2cGoodsAttrMapper b2cGoodsAttrMapper;
|
|
|
|
|
|
|
|
private static final BigDecimal HUNDRED = new BigDecimal("100");
|
|
private static final BigDecimal HUNDRED = new BigDecimal("100");
|
|
|
private static final BigDecimal COMMISSION_DEFAULT_RATE = new BigDecimal("0.01");
|
|
private static final BigDecimal COMMISSION_DEFAULT_RATE = new BigDecimal("0.01");
|
|
@@ -783,12 +793,17 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 供货:将本地商品推送到云商城
|
|
|
|
|
- * 对应PHP supply()中issupply==1的逻辑(929-1014行)
|
|
|
|
|
|
|
+ * 供货到云商城(对应PHP supply()中issupply==1的逻辑 + addGoods接口)
|
|
|
|
|
+ * 流程:1.保存SPU基础信息 → 2.保存图片 → 3.保存SKU → 4.更新上架状态
|
|
|
*/
|
|
*/
|
|
|
private void supplyGoodsToMall(ImsEweiShopGoods item, Integer storeid, Integer cate, Integer uniacid) {
|
|
private void supplyGoodsToMall(ImsEweiShopGoods item, Integer storeid, Integer cate, Integer uniacid) {
|
|
|
Long goodsId = item.getId();
|
|
Long goodsId = item.getId();
|
|
|
|
|
|
|
|
|
|
+ // 【Bug修复】查重前置:是否已在云商城供货(通过gd_id判断),避免无效查询
|
|
|
|
|
+ if (item.getGdId() != null && item.getGdId() > 0) {
|
|
|
|
|
+ throw new ApiException("商品已经供货");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 多规格时取最大重量
|
|
// 多规格时取最大重量
|
|
|
if (item.getHasoption() != null && item.getHasoption() == 1) {
|
|
if (item.getHasoption() != null && item.getHasoption() == 1) {
|
|
|
ImsEweiShopGoodsOption maxWeightOpt = optionService.getOne(new LambdaQueryWrapper<ImsEweiShopGoodsOption>()
|
|
ImsEweiShopGoodsOption maxWeightOpt = optionService.getOne(new LambdaQueryWrapper<ImsEweiShopGoodsOption>()
|
|
@@ -801,26 +816,53 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 构建供货数据
|
|
|
|
|
- Map<String, Object> addgoods = new LinkedHashMap<>();
|
|
|
|
|
- addgoods.put("gd_name", item.getTitle());
|
|
|
|
|
- addgoods.put("shop_id", storeid);
|
|
|
|
|
- addgoods.put("pt_id", cate);
|
|
|
|
|
- addgoods.put("gd_weight", item.getWeight());
|
|
|
|
|
- addgoods.put("gd_price", item.getMarketprice()); // 供货中心售价=商城售价
|
|
|
|
|
- addgoods.put("mk_price", item.getProductprice()); // 市场价
|
|
|
|
|
- addgoods.put("cost_price", item.getCostprice()); // 成本价/供货价
|
|
|
|
|
- addgoods.put("gd_stock", item.getTotal()); // 库存
|
|
|
|
|
- addgoods.put("msg1", item.getContent()); // 商品详情
|
|
|
|
|
- addgoods.put("uniacid", uniacid);
|
|
|
|
|
- addgoods.put("merchid", 0);
|
|
|
|
|
- addgoods.put("storeid", 0);
|
|
|
|
|
- addgoods.put("goodsid", goodsId.intValue());
|
|
|
|
|
-
|
|
|
|
|
- // 图片处理:thumb + thumb_url → imgsInfo数组
|
|
|
|
|
|
|
+ // 构建图片列表
|
|
|
|
|
+ List<String> imgsInfo = buildGoodsImages(item, goodsId);
|
|
|
|
|
+ // 构建规格列表
|
|
|
|
|
+ List<ImsEweiShopGoodsSpec> specs = specService.list(new LambdaQueryWrapper<ImsEweiShopGoodsSpec>()
|
|
|
|
|
+ .eq(ImsEweiShopGoodsSpec::getGoodsid, goodsId.intValue())
|
|
|
|
|
+ .eq(ImsEweiShopGoodsSpec::getUniacid, uniacid));
|
|
|
|
|
+ // 构建SKU选项列表
|
|
|
|
|
+ List<ImsEweiShopGoodsOption> options = optionService.list(new LambdaQueryWrapper<ImsEweiShopGoodsOption>()
|
|
|
|
|
+ .eq(ImsEweiShopGoodsOption::getGoodsid, goodsId.intValue())
|
|
|
|
|
+ .eq(ImsEweiShopGoodsOption::getUniacid, uniacid));
|
|
|
|
|
+
|
|
|
|
|
+ Timestamp now = new Timestamp(System.currentTimeMillis());
|
|
|
|
|
+
|
|
|
|
|
+ // Step 1: 保存商品SPU基础信息
|
|
|
|
|
+ Integer gdId = saveSpuToCloudMall(item, storeid, cate, uniacid, now);
|
|
|
|
|
+ log.info("云商城插入商品SPU成功 goodsId={}, gdId={}", goodsId, gdId);
|
|
|
|
|
+
|
|
|
|
|
+ // Step 2: 保存商品图片
|
|
|
|
|
+ saveImagesToCloudMall(gdId, imgsInfo, now);
|
|
|
|
|
+
|
|
|
|
|
+ // Step 3: 保存SKU信息(含属性映射)
|
|
|
|
|
+ saveSkusToCloudMall(gdId, storeid, item, specs, options, uniacid, cate, now);
|
|
|
|
|
+
|
|
|
|
|
+ // Step 4: 更新上架状态
|
|
|
|
|
+ B2cGoodsSpuInOnline updateSpu = new B2cGoodsSpuInOnline();
|
|
|
|
|
+ updateSpu.setGdId(gdId);
|
|
|
|
|
+ updateSpu.setIsOnSale(1);
|
|
|
|
|
+ if (!b2cGoodsSpuInOnlineService.updateById(updateSpu)) {
|
|
|
|
|
+ throw new ApiException("商品上架失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("云商城商品上架成功 goodsId={}, gdId={}", goodsId, gdId);
|
|
|
|
|
+
|
|
|
|
|
+ // 回写云商城商品ID & 供货
|
|
|
|
|
+ yunMallGoodsService.saveGoods(gdId.toString(), 1);
|
|
|
|
|
+ ImsEweiShopGoods update = new ImsEweiShopGoods();
|
|
|
|
|
+ update.setId(goodsId);
|
|
|
|
|
+ update.setGdId(gdId);
|
|
|
|
|
+ goodsService.updateById(update);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建商品图片列表:thumb首图 + thumb_url扩展图
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<String> buildGoodsImages(ImsEweiShopGoods item, Long goodsId) {
|
|
|
List<String> imgsInfo = new ArrayList<>();
|
|
List<String> imgsInfo = new ArrayList<>();
|
|
|
if (item.getThumb() != null) {
|
|
if (item.getThumb() != null) {
|
|
|
- imgsInfo.add(item.getThumb()); // 首图
|
|
|
|
|
|
|
+ imgsInfo.add(item.getThumb());
|
|
|
}
|
|
}
|
|
|
if (item.getThumbUrl() != null && !item.getThumbUrl().isEmpty()) {
|
|
if (item.getThumbUrl() != null && !item.getThumbUrl().isEmpty()) {
|
|
|
try {
|
|
try {
|
|
@@ -832,95 +874,324 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
|
|
|
log.warn("thumb_url解析失败 goodsId={}", goodsId, e);
|
|
log.warn("thumb_url解析失败 goodsId={}", goodsId, e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- addgoods.put("imgsInfo", JSON.toJSONString(imgsInfo));
|
|
|
|
|
-
|
|
|
|
|
- // 规格列表
|
|
|
|
|
- List<ImsEweiShopGoodsSpec> specs = specService.list(new LambdaQueryWrapper<ImsEweiShopGoodsSpec>()
|
|
|
|
|
- .eq(ImsEweiShopGoodsSpec::getGoodsid, goodsId.intValue())
|
|
|
|
|
- .eq(ImsEweiShopGoodsSpec::getUniacid, uniacid));
|
|
|
|
|
|
|
+ return imgsInfo;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- List<Map<String, Object>> specsList = new ArrayList<>();
|
|
|
|
|
- for (ImsEweiShopGoodsSpec spec : specs) {
|
|
|
|
|
- if (spec.getTitle() == null || spec.getTitle().isEmpty()) {
|
|
|
|
|
- throw new ApiException("规格名称为空不能供货");
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 保存商品SPU基础信息到云商城(对应 PHP _saveAddBaseinfo)
|
|
|
|
|
+ * 包含:品牌ID查找、品类路径构建、佣金比例查询
|
|
|
|
|
+ * @return 生成的gdId
|
|
|
|
|
+ */
|
|
|
|
|
+ private Integer saveSpuToCloudMall(ImsEweiShopGoods item, Integer storeid, Integer cate,
|
|
|
|
|
+ Integer uniacid, Timestamp now) {
|
|
|
|
|
+ B2cGoodsSpuInOnline spu = new B2cGoodsSpuInOnline();
|
|
|
|
|
+ spu.setGdName(item.getTitle());
|
|
|
|
|
+ spu.setShopId(storeid);
|
|
|
|
|
+ spu.setPtId(cate);
|
|
|
|
|
+ spu.setGdWeight(item.getWeight() != null ? item.getWeight().doubleValue() : 0.0);
|
|
|
|
|
+ spu.setGdColor("#000000");
|
|
|
|
|
+ spu.setGdNum("QY" + System.currentTimeMillis() + String.format("%04d", (int) (Math.random() * 10000)));
|
|
|
|
|
+ // 商品详情描述(对应PHP _saveDetailedDescription → _writeText)
|
|
|
|
|
+ // PHP原始逻辑:将content写入NFS文件(1.txt),gd_desc存储文件URL数组
|
|
|
|
|
+ // Java直连DB:无法访问PHP NFS,直接存储HTML内容到gd_desc字段
|
|
|
|
|
+ // 原始Java代码仅传递msg1=content,未传msg2/msg3
|
|
|
|
|
+ spu.setGdDesc(item.getContent());
|
|
|
|
|
+ spu.setUniacid(uniacid);
|
|
|
|
|
+ spu.setMerchid(0);
|
|
|
|
|
+ spu.setStoreid(0);
|
|
|
|
|
+ spu.setGoodsid(item.getId().intValue());
|
|
|
|
|
+ spu.setIsOnSale(0); // 先设为0,Step4再更新为上架
|
|
|
|
|
+ spu.setIsDel(0);
|
|
|
|
|
+ spu.setAuditStatus(1); // 企悦供货免审
|
|
|
|
|
+ spu.setCreateUsername("企悦接口");
|
|
|
|
|
+ spu.setUpdUsername("企悦接口");
|
|
|
|
|
+ spu.setCreateTime(now);
|
|
|
|
|
+ spu.setUpdTime(now);
|
|
|
|
|
+
|
|
|
|
|
+ // 查询品牌ID(对应PHP中查找/创建"其它"品牌逻辑)
|
|
|
|
|
+ try {
|
|
|
|
|
+ Integer brandId = b2cGoodsSpuInOnlineMapper.findBrandIdByName("其它");
|
|
|
|
|
+ if (brandId != null) {
|
|
|
|
|
+ spu.setBrandId(brandId);
|
|
|
}
|
|
}
|
|
|
- Map<String, Object> specMap = new LinkedHashMap<>();
|
|
|
|
|
- specMap.put("id", spec.getId());
|
|
|
|
|
- specMap.put("title", spec.getTitle());
|
|
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("查询品牌ID失败,跳过 ptId={}", cate, e);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- List<ImsEweiShopGoodsSpecItem> speItems = specItemService.list(
|
|
|
|
|
- new LambdaQueryWrapper<ImsEweiShopGoodsSpecItem>()
|
|
|
|
|
- .eq(ImsEweiShopGoodsSpecItem::getSpecid, spec.getId().intValue())
|
|
|
|
|
- .eq(ImsEweiShopGoodsSpecItem::getUniacid, uniacid));
|
|
|
|
|
|
|
+ // 构建品类路径cat_ids(对应PHP getCategoryListByid)
|
|
|
|
|
+ try {
|
|
|
|
|
+ String catIds = buildCategoryPath(cate);
|
|
|
|
|
+ if (catIds != null && !catIds.isEmpty()) {
|
|
|
|
|
+ spu.setCatIds(catIds);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("构建cat_ids失败,跳过 ptId={}", cate, e);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- List<Map<String, Object>> valuesList = new ArrayList<>();
|
|
|
|
|
- for (ImsEweiShopGoodsSpecItem speItem : speItems) {
|
|
|
|
|
- Map<String, Object> valMap = new LinkedHashMap<>();
|
|
|
|
|
- valMap.put("id", speItem.getId());
|
|
|
|
|
- valMap.put("title", speItem.getTitle());
|
|
|
|
|
- valMap.put("sku_img", speItem.getThumb() != null ? speItem.getThumb() : "");
|
|
|
|
|
- valuesList.add(valMap);
|
|
|
|
|
|
|
+ // 查询佣金比例(对应PHP中从product_type查询ledger_ratio)
|
|
|
|
|
+ try {
|
|
|
|
|
+ Map<String, Object> commissionMap = b2cGoodsSpuInOnlineMapper.findCommissionByPtId(cate);
|
|
|
|
|
+ if (commissionMap != null) {
|
|
|
|
|
+ BigDecimal ledgerRatio = toBigDecimal(commissionMap.get("ledger_ratio"));
|
|
|
|
|
+ BigDecimal tgLedgerRatio = toBigDecimal(commissionMap.get("tg_ledger_ratio"));
|
|
|
|
|
+ spu.setCommissionRatio(ledgerRatio);
|
|
|
|
|
+ spu.setCommissionSetRatio(ledgerRatio);
|
|
|
|
|
+ spu.setTgCommissionRatio(tgLedgerRatio);
|
|
|
|
|
+ spu.setTgCommissionSetRatio(tgLedgerRatio);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ spu.setCommissionRatio(BigDecimal.ZERO);
|
|
|
|
|
+ spu.setCommissionSetRatio(BigDecimal.ZERO);
|
|
|
|
|
+ spu.setTgCommissionRatio(BigDecimal.ZERO);
|
|
|
|
|
+ spu.setTgCommissionSetRatio(BigDecimal.ZERO);
|
|
|
}
|
|
}
|
|
|
- specMap.put("values", valuesList);
|
|
|
|
|
- specsList.add(specMap);
|
|
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("查询佣金比例失败,使用默认值0 ptId={}", cate, e);
|
|
|
|
|
+ spu.setCommissionRatio(BigDecimal.ZERO);
|
|
|
|
|
+ spu.setCommissionSetRatio(BigDecimal.ZERO);
|
|
|
|
|
+ spu.setTgCommissionRatio(BigDecimal.ZERO);
|
|
|
|
|
+ spu.setTgCommissionSetRatio(BigDecimal.ZERO);
|
|
|
}
|
|
}
|
|
|
- addgoods.put("specslist", JSON.toJSONString(specsList));
|
|
|
|
|
|
|
+ spu.setCommissionTime(now);
|
|
|
|
|
+ spu.setTgCommissionTime(now);
|
|
|
|
|
|
|
|
- // SKU选项列表
|
|
|
|
|
- List<ImsEweiShopGoodsOption> options = optionService.list(new LambdaQueryWrapper<ImsEweiShopGoodsOption>()
|
|
|
|
|
- .eq(ImsEweiShopGoodsOption::getGoodsid, goodsId.intValue())
|
|
|
|
|
- .eq(ImsEweiShopGoodsOption::getUniacid, uniacid));
|
|
|
|
|
|
|
+ if (!b2cGoodsSpuInOnlineService.save(spu)) {
|
|
|
|
|
+ throw new ApiException("保存商品基础信息失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ return spu.getGdId();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- List<Map<String, Object>> optionsList = new ArrayList<>();
|
|
|
|
|
- for (ImsEweiShopGoodsOption opt : options) {
|
|
|
|
|
- Map<String, Object> optMap = new LinkedHashMap<>();
|
|
|
|
|
- optMap.put("id", opt.getId());
|
|
|
|
|
- optMap.put("title", opt.getTitle());
|
|
|
|
|
- optMap.put("gd_weight", opt.getWeight());
|
|
|
|
|
- optMap.put("gd_price", opt.getMarketprice()); // 供货中心售价=商城售价
|
|
|
|
|
- optMap.put("mk_price", opt.getProductprice()); // 市场价
|
|
|
|
|
- optMap.put("cost_price", item.getCostprice()); // 供货价统一取商品级
|
|
|
|
|
- optMap.put("gd_stock", opt.getStock());
|
|
|
|
|
- optMap.put("specs", opt.getSpecs());
|
|
|
|
|
- optionsList.add(optMap);
|
|
|
|
|
- }
|
|
|
|
|
- addgoods.put("optionslist", JSON.toJSONString(optionsList));
|
|
|
|
|
-
|
|
|
|
|
- // 查重:是否已在云商城供货(通过gd_id判断)
|
|
|
|
|
- if (item.getGdId() != null && item.getGdId() > 0) {
|
|
|
|
|
- throw new ApiException("商品已经供货");
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建品类路径(对应PHP getCategoryListByid)
|
|
|
|
|
+ * 从叶子节点递归向上查找,最终组装为“根ID,二级ID,...,叶子ID”格式
|
|
|
|
|
+ */
|
|
|
|
|
+ private String buildCategoryPath(Integer ptId) {
|
|
|
|
|
+ Map<String, Object> category = b2cGoodsSpuInOnlineMapper.findCategoryByPtId(ptId);
|
|
|
|
|
+ if (category == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ List<Integer> cateIds = new ArrayList<>();
|
|
|
|
|
+ cateIds.add(toInteger(category.get("cate_id")));
|
|
|
|
|
+
|
|
|
|
|
+ // 向上递归查找父级,最多4层防止无限循环
|
|
|
|
|
+ Object parentId = category.get("parent_id");
|
|
|
|
|
+ int maxLevel = 4;
|
|
|
|
|
+ while (parentId != null && toInteger(parentId) > 0 && maxLevel-- > 0) {
|
|
|
|
|
+ Map<String, Object> parent = b2cGoodsSpuInOnlineMapper.findCategoryByCateId(toInteger(parentId));
|
|
|
|
|
+ if (parent == null) break;
|
|
|
|
|
+ cateIds.add(toInteger(parent.get("cate_id")));
|
|
|
|
|
+ parentId = parent.get("parent_id");
|
|
|
}
|
|
}
|
|
|
|
|
+ // 反转为从根到叶子的顺序
|
|
|
|
|
+ Collections.reverse(cateIds);
|
|
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
|
|
+ for (int i = 0; i < cateIds.size(); i++) {
|
|
|
|
|
+ if (i > 0) sb.append(",");
|
|
|
|
|
+ sb.append(cateIds.get(i));
|
|
|
|
|
+ }
|
|
|
|
|
+ return sb.toString();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 调用云商城接口创建商品
|
|
|
|
|
- String addGoodsUrl = mallHost + "/addGoods";
|
|
|
|
|
- String content;
|
|
|
|
|
- try {
|
|
|
|
|
- content = HttpUtil.restTemplatePostCurl(addGoodsUrl, addgoods);
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.error("云商城addGoods接口调用失败 goodsId={}", goodsId, e);
|
|
|
|
|
- throw new ApiException("云商城接口调用失败: " + e.getMessage());
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 保存商品图片到云商城(对应 PHP _saveImgs)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void saveImagesToCloudMall(Integer gdId, List<String> imgsInfo, Timestamp now) {
|
|
|
|
|
+ if (imgsInfo == null || imgsInfo.isEmpty()) {
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
+ for (int i = 0; i < imgsInfo.size(); i++) {
|
|
|
|
|
+ B2cGoodsImgInOnline img = new B2cGoodsImgInOnline();
|
|
|
|
|
+ img.setGdId(gdId);
|
|
|
|
|
+ img.setGdImg(imgsInfo.get(i));
|
|
|
|
|
+ img.setAttrValIds("");
|
|
|
|
|
+ img.setIsDefault(i == 0 ? 1 : 0);
|
|
|
|
|
+ img.setStatus(1);
|
|
|
|
|
+ img.setCreateUsername("企悦接口");
|
|
|
|
|
+ img.setCreateTime(now);
|
|
|
|
|
+ img.setImgSort(i);
|
|
|
|
|
+ b2cGoodsImgInOnlineService.save(img);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- log.info("云商城插入商品 goodsId={}, uniacid={}, url={}, response={}", goodsId, uniacid, addGoodsUrl, content);
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 保存SKU信息到云商城(对应 PHP _setSkuInfo / _noSaleAttrSetSku)
|
|
|
|
|
+ * 包含:属性创建/映射 + SKU持久化 + Redis库存缓存
|
|
|
|
|
+ */
|
|
|
|
|
+ private void saveSkusToCloudMall(Integer gdId, Integer storeid, ImsEweiShopGoods item,
|
|
|
|
|
+ List<ImsEweiShopGoodsSpec> specs,
|
|
|
|
|
+ List<ImsEweiShopGoodsOption> options,
|
|
|
|
|
+ Integer uniacid, Integer cate, Timestamp now) {
|
|
|
|
|
+ // 校验规格名称
|
|
|
|
|
+ if (specs != null) {
|
|
|
|
|
+ for (ImsEweiShopGoodsSpec spec : specs) {
|
|
|
|
|
+ if (spec.getTitle() == null || spec.getTitle().isEmpty()) {
|
|
|
|
|
+ throw new ApiException("规格名称为空不能供货");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- JSONObject result = JSON.parseObject(content);
|
|
|
|
|
- if (result == null || result.getIntValue("head") != 200) {
|
|
|
|
|
- String msg = result != null && result.getString("msg") != null ? result.getString("msg") : "供货失败!";
|
|
|
|
|
- throw new ApiException(msg);
|
|
|
|
|
|
|
+ boolean hasSpecs = specs != null && !specs.isEmpty() && options != null && !options.isEmpty();
|
|
|
|
|
+ if (hasSpecs) {
|
|
|
|
|
+ // 有规格:先创建/更新属性,再保存SKU(对应PHP _setSkuInfo)
|
|
|
|
|
+ // Step A: 为每个规格创建/更新属性记录(对应PHP _saveAttr)
|
|
|
|
|
+ Integer ptId = cate != null ? cate : 0;
|
|
|
|
|
+ List<Integer> attrIds = saveAttrsToCloudMall(specs, uniacid, ptId);
|
|
|
|
|
+
|
|
|
|
|
+ // Step B: 保存商品属性关联到SPU(对应PHP _saveGoodsAttr)
|
|
|
|
|
+ saveGoodsAttrsToSpu(gdId, attrIds);
|
|
|
|
|
+
|
|
|
|
|
+ // Step C: 保存SKU,sale_attrs转换为云商城attrValId(对应PHP _saveSku)
|
|
|
|
|
+ for (ImsEweiShopGoodsOption opt : options) {
|
|
|
|
|
+ B2cGoodsSkuInOnline sku = new B2cGoodsSkuInOnline();
|
|
|
|
|
+ sku.setGdId(gdId);
|
|
|
|
|
+ sku.setGdPrice(opt.getMarketprice() != null ? opt.getMarketprice() : BigDecimal.ZERO);
|
|
|
|
|
+ sku.setCostPrice(item.getCostprice() != null ? item.getCostprice() : BigDecimal.ZERO);
|
|
|
|
|
+ sku.setMkPrice(opt.getProductprice() != null ? opt.getProductprice() : BigDecimal.ZERO);
|
|
|
|
|
+ sku.setGdStock(opt.getStock() != null ? opt.getStock() : 0);
|
|
|
|
|
+ sku.setShopId(storeid);
|
|
|
|
|
+ // 将企悦spec_item_id转换为云商城attrValId(对应PHP _saveSku中的sale_attrs映射)
|
|
|
|
|
+ sku.setSaleAttrs(mapSpecsToAttrValIds(opt.getSpecs()));
|
|
|
|
|
+ sku.setIsDel(0);
|
|
|
|
|
+ sku.setCreateUsername("企悦接口");
|
|
|
|
|
+ sku.setCreateTime(now);
|
|
|
|
|
+ sku.setUpdUsername("企悦接口");
|
|
|
|
|
+ sku.setUpdTime(now);
|
|
|
|
|
+ sku.setQyId(opt.getId() != null ? opt.getId().intValue() : null);
|
|
|
|
|
+ b2cGoodsSkuInOnlineService.save(sku);
|
|
|
|
|
+
|
|
|
|
|
+ // Redis缓存:对应PHP _saveSku中的redis操作
|
|
|
|
|
+ if (sku.getSkuId() != null && opt.getId() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String optionKey = "option_" + opt.getId().intValue();
|
|
|
|
|
+ redisUtils.set(optionKey, String.valueOf(sku.getSkuId()));
|
|
|
|
|
+ redisUtils.set(String.valueOf(sku.getSkuId()), String.valueOf(sku.getGdStock()));
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("Redis缓存多规格SKU库存失败 gdId={}, optionId={}", gdId, opt.getId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 无规格:单SKU(对应PHP _noSaleAttrSetSku)
|
|
|
|
|
+ B2cGoodsSkuInOnline sku = new B2cGoodsSkuInOnline();
|
|
|
|
|
+ sku.setGdId(gdId);
|
|
|
|
|
+ sku.setGdPrice(item.getMarketprice() != null ? item.getMarketprice() : BigDecimal.ZERO);
|
|
|
|
|
+ sku.setCostPrice(item.getCostprice() != null ? item.getCostprice() : BigDecimal.ZERO);
|
|
|
|
|
+ sku.setMkPrice(item.getProductprice() != null ? item.getProductprice() : BigDecimal.ZERO);
|
|
|
|
|
+ sku.setGdStock(item.getTotal() != null ? item.getTotal() : 0);
|
|
|
|
|
+ sku.setShopId(storeid);
|
|
|
|
|
+ sku.setSaleAttrs("");
|
|
|
|
|
+ sku.setIsDel(0);
|
|
|
|
|
+ sku.setCreateUsername("企悦接口");
|
|
|
|
|
+ sku.setCreateTime(now);
|
|
|
|
|
+ sku.setUpdUsername("企悦接口");
|
|
|
|
|
+ sku.setUpdTime(now);
|
|
|
|
|
+ b2cGoodsSkuInOnlineService.save(sku);
|
|
|
|
|
+
|
|
|
|
|
+ // Redis缓存:对应PHP _noSaleAttrSetSku中的redis操作
|
|
|
|
|
+ if (sku.getSkuId() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String goodsKey = "goods_" + gdId;
|
|
|
|
|
+ redisUtils.set(goodsKey, String.valueOf(sku.getSkuId()));
|
|
|
|
|
+ redisUtils.set(String.valueOf(sku.getSkuId()), String.valueOf(sku.getGdStock()));
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("Redis缓存单SKU库存失败 gdId={}", gdId, e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 回写云商城商品ID
|
|
|
|
|
- Integer gdId = result.getJSONObject("result") != null
|
|
|
|
|
- ? result.getJSONObject("result").getInteger("goods_id") : null;
|
|
|
|
|
- if (gdId != null) {
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 为每个规格创建/更新云商城属性记录(对应PHP _saveAttr)
|
|
|
|
|
+ * 流程:查询attr_id→创建/更新attr→维护pt_attr→删除旧attr_value→插入新attr_value
|
|
|
|
|
+ * @return 所有规格对应的attrId列表
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<Integer> saveAttrsToCloudMall(List<ImsEweiShopGoodsSpec> specs, Integer uniacid, Integer ptId) {
|
|
|
|
|
+ List<Integer> attrIds = new ArrayList<>();
|
|
|
|
|
+ for (ImsEweiShopGoodsSpec spec : specs) {
|
|
|
|
|
+ Integer specId = spec.getId().intValue();
|
|
|
|
|
+ // 1. 查询是否已有对应属性
|
|
|
|
|
+ Integer attrId = b2cGoodsAttrMapper.findAttrIdByQyId(specId);
|
|
|
|
|
+ if (attrId != null) {
|
|
|
|
|
+ // 已有属性,更新名称
|
|
|
|
|
+ b2cGoodsAttrMapper.updateAttr(attrId, spec.getTitle());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 新增属性
|
|
|
|
|
+ Map<String, Object> params = new HashMap<>();
|
|
|
|
|
+ params.put("attrName", spec.getTitle());
|
|
|
|
|
+ params.put("qyId", specId);
|
|
|
|
|
+ b2cGoodsAttrMapper.insertAttrReturnId(params);
|
|
|
|
|
+ attrId = (Integer) params.get("attrId");
|
|
|
|
|
+ }
|
|
|
|
|
+ attrIds.add(attrId);
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 维护品类属性关联(b2c_pt_attr)
|
|
|
|
|
+ if (ptId != null && ptId > 0) {
|
|
|
|
|
+ int count = b2cGoodsAttrMapper.countPtAttr(ptId, attrId);
|
|
|
|
|
+ if (count > 0) {
|
|
|
|
|
+ b2cGoodsAttrMapper.updatePtAttr(ptId, attrId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ b2cGoodsAttrMapper.insertPtAttr(ptId, attrId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- //供货
|
|
|
|
|
- yunMallGoodsService.saveGoods(gdId.toString(),1);
|
|
|
|
|
|
|
+ // 3. 删除该属性下旧的属性值,重新插入
|
|
|
|
|
+ b2cGoodsAttrMapper.deleteAttrValuesByAttrId(attrId);
|
|
|
|
|
|
|
|
- ImsEweiShopGoods update = new ImsEweiShopGoods();
|
|
|
|
|
- update.setId(goodsId);
|
|
|
|
|
- update.setGdId(gdId);
|
|
|
|
|
- goodsService.updateById(update);
|
|
|
|
|
|
|
+ // 4. 查询规格项并插入属性值
|
|
|
|
|
+ List<ImsEweiShopGoodsSpecItem> specItems = specItemService.list(
|
|
|
|
|
+ new LambdaQueryWrapper<ImsEweiShopGoodsSpecItem>()
|
|
|
|
|
+ .eq(ImsEweiShopGoodsSpecItem::getSpecid, specId)
|
|
|
|
|
+ .eq(ImsEweiShopGoodsSpecItem::getUniacid, uniacid));
|
|
|
|
|
+ for (ImsEweiShopGoodsSpecItem specItem : specItems) {
|
|
|
|
|
+ b2cGoodsAttrMapper.insertAttrValue(
|
|
|
|
|
+ specItem.getTitle(), attrId, specItem.getId().intValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return attrIds;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 保存商品属性关联到SPU的sale_attrs字段(对应PHP _saveGoodsAttr)
|
|
|
|
|
+ * 构建格式:["attrId_attrValId1", "attrId_attrValId2", ...]
|
|
|
|
|
+ */
|
|
|
|
|
+ private void saveGoodsAttrsToSpu(Integer gdId, List<Integer> attrIds) {
|
|
|
|
|
+ List<String> saleAttrList = new ArrayList<>();
|
|
|
|
|
+ for (Integer attrId : attrIds) {
|
|
|
|
|
+ List<Integer> attrValIds = b2cGoodsAttrMapper.findAttrValIdsByAttrId(attrId);
|
|
|
|
|
+ if (attrValIds != null) {
|
|
|
|
|
+ for (Integer attrValId : attrValIds) {
|
|
|
|
|
+ saleAttrList.add(attrId + "_" + attrValId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!saleAttrList.isEmpty()) {
|
|
|
|
|
+ B2cGoodsSpuInOnline updateSpu = new B2cGoodsSpuInOnline();
|
|
|
|
|
+ updateSpu.setGdId(gdId);
|
|
|
|
|
+ updateSpu.setSaleAttrs(JSON.toJSONString(saleAttrList));
|
|
|
|
|
+ b2cGoodsSpuInOnlineService.updateById(updateSpu);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将企悦specItemId串转换为云商城attrValId串(对应PHP _saveSku中的sale_attrs映射)
|
|
|
|
|
+ * 例如:输入 "10_20" → 输出 "201_301"(其中201、301是b2c_attr_value中对应qy_id=10、20的attr_val_id)
|
|
|
|
|
+ */
|
|
|
|
|
+ private String mapSpecsToAttrValIds(String specs) {
|
|
|
|
|
+ if (specs == null || specs.isEmpty()) {
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ String[] qyIds = specs.split("_");
|
|
|
|
|
+ StringBuilder mappedAttrs = new StringBuilder();
|
|
|
|
|
+ for (int i = 0; i < qyIds.length; i++) {
|
|
|
|
|
+ Integer qyId = Integer.valueOf(qyIds[i].trim());
|
|
|
|
|
+ Integer attrValId = b2cGoodsAttrMapper.findAttrValIdByQyId(qyId);
|
|
|
|
|
+ if (i > 0) mappedAttrs.append("_");
|
|
|
|
|
+ mappedAttrs.append(attrValId != null ? attrValId : qyId);
|
|
|
|
|
+ }
|
|
|
|
|
+ return mappedAttrs.toString();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("规格ID映射失败,使用原始值 specs={}", specs, e);
|
|
|
|
|
+ return specs;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -985,4 +1256,25 @@ public class CommodityProcureServiceImpl implements CommodityProcureService {
|
|
|
log.info("供货/停止供货处理完成 goodsId={}, issupply={}", goodsId, issupply);
|
|
log.info("供货/停止供货处理完成 goodsId={}, issupply={}", goodsId, issupply);
|
|
|
return Result.success();
|
|
return Result.success();
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 安全转换为BigDecimal
|
|
|
|
|
+ */
|
|
|
|
|
+ private BigDecimal toBigDecimal(Object val) {
|
|
|
|
|
+ if (val == null) return BigDecimal.ZERO;
|
|
|
|
|
+ if (val instanceof BigDecimal) return (BigDecimal) val;
|
|
|
|
|
+ if (val instanceof Number) return new BigDecimal(val.toString());
|
|
|
|
|
+ try { return new BigDecimal(val.toString()); } catch (Exception e) { return BigDecimal.ZERO; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 安全转换为Integer
|
|
|
|
|
+ */
|
|
|
|
|
+ private Integer toInteger(Object val) {
|
|
|
|
|
+ if (val == null) return 0;
|
|
|
|
|
+ if (val instanceof Integer) return (Integer) val;
|
|
|
|
|
+ if (val instanceof Number) return ((Number) val).intValue();
|
|
|
|
|
+ try { return Integer.valueOf(val.toString()); } catch (Exception e) { return 0; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|