diff --git a/service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphPublishService.java b/service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphPublishService.java index 396f0bf7..84388b58 100644 --- a/service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphPublishService.java +++ b/service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphPublishService.java @@ -235,11 +235,7 @@ public class ExternalSphPublishService { root.put("head_imgs", head); root.put("deliver_method", 0); root.put("deliver_acct_type", new JSONArray()); - JSONArray catsV2 = new JSONArray(); - JSONObject leaf = new JSONObject(); - long leafCatId = resolveLeafCatId(req, imgs.headImgUrls(), accessToken); - leaf.put("cat_id", String.valueOf(leafCatId)); - catsV2.add(leaf); + JSONArray catsV2 = resolveCatsV2OrThrow(req, imgs.headImgUrls(), accessToken); root.put("cats_v2", catsV2); JSONObject extra = new JSONObject(); extra.put("seven_day_return", 0); @@ -269,13 +265,15 @@ public class ExternalSphPublishService { return root; } - private long resolveLeafCatId(ExternalGoodsUpsertRequest req, List headImgUrls, String accessToken) { - long fixedCat = props.getFixedLeafCatIdV2(); + private JSONArray resolveCatsV2OrThrow(ExternalGoodsUpsertRequest req, List headImgUrls, String accessToken) { if (!StringUtils.hasText(props.getProductClassifyUrl())) { - return fixedCat; + throw new IllegalStateException("external.sph.product-classify-url 未配置,无法获取推荐类目"); } - if (!StringUtils.hasText(accessToken) || CollectionUtils.isEmpty(headImgUrls)) { - return fixedCat; + if (!StringUtils.hasText(accessToken)) { + throw new IllegalStateException("缺少 accessToken,无法调用类目推荐接口"); + } + if (CollectionUtils.isEmpty(headImgUrls)) { + throw new IllegalStateException("缺少主图,无法调用类目推荐接口"); } try { JSONObject body = new JSONObject(); @@ -289,9 +287,6 @@ public class ExternalSphPublishService { head.add(u); } } - if (head.isEmpty()) { - return fixedCat; - } body.put("head_imgs", head); String url = props.getProductClassifyUrl(); String fullUrl = url + (url.contains("?") ? "&" : "?") @@ -299,49 +294,66 @@ public class ExternalSphPublishService { String raw = httpClient.postJson(fullUrl, body.toJSONString(), Duration.ofSeconds(Math.max(5, props.getHttpReadTimeoutSeconds()))); if (!WeixinShopEcHttpClient.isBizOk(raw)) { - log.warn("[SPH] classify failed shopId={} outGoodsId={} err={} snippet={}", - req.getShopId(), req.getOutGoodsId(), WeixinShopEcHttpClient.formatWxError(raw), - WeixinShopEcLogSupport.snippet(raw, 500)); - return fixedCat; + throw new IllegalStateException("类目推荐失败: " + WeixinShopEcHttpClient.formatWxError(raw)); } - Long recommended = parseRecommendedLeafCatId(raw); - if (recommended == null || recommended <= 0) { - return fixedCat; + JSONArray catsV2 = parseRecommendedCatsV2(raw); + if (catsV2 == null || catsV2.isEmpty()) { + throw new IllegalStateException("类目推荐成功但未返回可用类目链"); } - log.info("[SPH] classify ok shopId={} outGoodsId={} recommendedLeafCatId={} fixedLeafCatId={}", - req.getShopId(), req.getOutGoodsId(), recommended, fixedCat); - return recommended; + String leafCat = catsV2.getJSONObject(catsV2.size() - 1).getString("cat_id"); + log.info("[SPH] classify ok shopId={} outGoodsId={} catsV2Size={} leafCatId={} catsV2={}", + req.getShopId(), req.getOutGoodsId(), catsV2.size(), leafCat, catsV2); + return catsV2; + } catch (IllegalStateException e) { + throw e; } catch (Exception e) { - log.warn("[SPH] classify exception shopId={} outGoodsId={} err={}", - req.getShopId(), req.getOutGoodsId(), e.getMessage()); - return fixedCat; + throw new IllegalStateException("类目推荐异常: " + e.getMessage(), e); } } - private static Long parseRecommendedLeafCatId(String raw) { + private static JSONArray parseRecommendedCatsV2(String raw) { JSONObject root = JSON.parseObject(raw); JSONArray categories = root.getJSONArray("categories"); if (categories == null || categories.isEmpty()) { return null; } - Long fallback = null; for (Object obj : categories) { if (!(obj instanceof JSONObject item)) { continue; } JSONObject cats = item.getJSONObject("cats"); - Long leaf = extractLeafCatId(cats); - if (leaf == null || leaf <= 0) { + JSONArray catInfo = cats == null ? null : cats.getJSONArray("cat_info"); + if (catInfo == null || catInfo.isEmpty()) { continue; } - if (fallback == null) { - fallback = leaf; - } if (hasCategoryAuth(item) || hasCategoryAuth(cats)) { - return leaf; + JSONArray out = new JSONArray(); + for (Object c : catInfo) { + if (!(c instanceof JSONObject cObj)) { + continue; + } + String catId = cObj.getString("cat_id"); + if (!StringUtils.hasText(catId) && cObj.containsKey("cat_id")) { + Object n = cObj.get("cat_id"); + catId = n == null ? null : String.valueOf(n); + } + if (!StringUtils.hasText(catId)) { + continue; + } + JSONObject one = new JSONObject(); + String catIdTrim = catId == null ? "" : catId.trim(); + if (!StringUtils.hasText(catIdTrim)) { + continue; + } + one.put("cat_id", catIdTrim); + out.add(one); + } + if (!out.isEmpty()) { + return out; + } } } - return fallback; + return null; } private static boolean hasCategoryAuth(JSONObject o) { @@ -360,37 +372,6 @@ public class ExternalSphPublishService { return false; } - private static Long extractLeafCatId(JSONObject cats) { - if (cats == null) { - return null; - } - JSONArray catInfo = cats.getJSONArray("cat_info"); - if (catInfo == null || catInfo.isEmpty()) { - return null; - } - for (int i = catInfo.size() - 1; i >= 0; i--) { - Object c = catInfo.get(i); - if (c instanceof JSONObject cObj) { - String catId = cObj.getString("cat_id"); - if (StringUtils.hasText(catId)) { - try { - return Long.parseLong(catId.trim()); - } catch (NumberFormatException ignore) { - // ignore and continue - } - } - if (cObj.containsKey("cat_id")) { - try { - return cObj.getLong("cat_id"); - } catch (Exception ignore) { - // ignore and continue - } - } - } - } - return null; - } - private JSONArray buildSkus(List skuRows, ExternalGoodsUpsertRequest req, String defaultThumbWxUrl, String accessToken) { JSONArray arr = new JSONArray();