diff --git a/api/erp-api/src/main/java/cn/qihangerp/erp/controller/ExternalPddGoodsController.java b/api/erp-api/src/main/java/cn/qihangerp/erp/controller/ExternalPddGoodsController.java
index 28caa501..0b175add 100644
--- a/api/erp-api/src/main/java/cn/qihangerp/erp/controller/ExternalPddGoodsController.java
+++ b/api/erp-api/src/main/java/cn/qihangerp/erp/controller/ExternalPddGoodsController.java
@@ -2,11 +2,13 @@ package cn.qihangerp.erp.controller;
import cn.qihangerp.common.AjaxResult;
import cn.qihangerp.model.request.ExternalPddGoodsDetailRequest;
+import cn.qihangerp.model.request.ExternalPddGoodsLatestCommitStatusRequest;
import cn.qihangerp.model.vo.ExternalPddGoodsDetailResultVo;
import cn.qihangerp.security.common.BaseController;
import cn.qihangerp.erp.config.ExternalGoodsApiLogProperties;
import cn.qihangerp.erp.support.ExternalGoodsRequestLogSupport;
import cn.qihangerp.service.external.ExternalPddGoodsDetailAppService;
+import cn.qihangerp.service.external.ExternalPddGoodsLatestCommitStatusAppService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
@@ -19,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
* 拼多多专用外部接口(与 {@code /external/goods/upsert} 编排解耦)。
*
* - {@code POST /external/pdd/goods/detail} — {@code pdd.goods.detail.get}
+ * - {@code POST /external/pdd/goods/latest-commit-status} — {@code pdd.goods.latest.commit.status.get}
*
* 改库存请使用 {@code POST /external/goods/pdd/quantity/update}(与 upsert 相同 out 键)。
*/
@@ -29,6 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
public class ExternalPddGoodsController extends BaseController {
private final ExternalPddGoodsDetailAppService externalPddGoodsDetailAppService;
+ private final ExternalPddGoodsLatestCommitStatusAppService externalPddGoodsLatestCommitStatusAppService;
private final ExternalGoodsApiLogProperties goodsApiLogProperties;
@PostMapping("/detail")
@@ -53,4 +57,28 @@ public class ExternalPddGoodsController extends BaseController {
}
return AjaxResult.success(vo);
}
+
+ @PostMapping("/latest-commit-status")
+ public AjaxResult latestCommitStatus(@RequestBody ExternalPddGoodsLatestCommitStatusRequest req) {
+ if (goodsApiLogProperties.isLogFullRequest()) {
+ log.info("[external/pdd/goods/latest-commit-status] goodsIdCount={}",
+ req != null && req.getPddGoodsIds() != null ? req.getPddGoodsIds().size() : 0);
+ }
+ if (req == null || req.getPddGoodsIds() == null || req.getPddGoodsIds().isEmpty()) {
+ return AjaxResult.error("参数错误:pddGoodsIds 不能为空");
+ }
+ if (req.getPddPopAuth() == null) {
+ return AjaxResult.error("参数错误:pddPopAuth 不能为空");
+ }
+ var auth = req.getPddPopAuth();
+ if (!StringUtils.hasText(auth.getAppKey()) || !StringUtils.hasText(auth.getAppSecret())
+ || !StringUtils.hasText(auth.getAccessToken())) {
+ return AjaxResult.error("参数错误:pddPopAuth 需提供 appKey、appSecret、accessToken");
+ }
+ ExternalPddGoodsDetailResultVo vo = externalPddGoodsLatestCommitStatusAppService.fetchLatestCommitStatus(req);
+ if (!Boolean.TRUE.equals(vo.getPopBizSuccess())) {
+ return AjaxResult.error(StringUtils.hasText(vo.getMessage()) ? vo.getMessage() : "pdd.goods.latest.commit.status.get 失败");
+ }
+ return AjaxResult.success(vo);
+ }
}
diff --git a/model/src/main/java/cn/qihangerp/model/request/ExternalPddGoodsLatestCommitStatusRequest.java b/model/src/main/java/cn/qihangerp/model/request/ExternalPddGoodsLatestCommitStatusRequest.java
new file mode 100644
index 00000000..074152fb
--- /dev/null
+++ b/model/src/main/java/cn/qihangerp/model/request/ExternalPddGoodsLatestCommitStatusRequest.java
@@ -0,0 +1,18 @@
+package cn.qihangerp.model.request;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * {@code POST /external/pdd/goods/latest-commit-status}:转发 {@code pdd.goods.latest.commit.status.get}。
+ * 凭证形态与 {@link ExternalPddGoodsDetailRequest#getPddPopAuth()} 一致。
+ */
+@Data
+public class ExternalPddGoodsLatestCommitStatusRequest {
+
+ /** 待查询的拼多多 {@code goods_id} 列表(将序列化为 POP 顶层 {@code goods_id_list}) */
+ private List pddGoodsIds;
+
+ private ExternalGoodsUpsertRequest.PddPopAuth pddPopAuth;
+}
diff --git a/service/src/main/java/cn/qihangerp/service/external/ExternalPddGoodsLatestCommitStatusAppService.java b/service/src/main/java/cn/qihangerp/service/external/ExternalPddGoodsLatestCommitStatusAppService.java
new file mode 100644
index 00000000..1f6077a8
--- /dev/null
+++ b/service/src/main/java/cn/qihangerp/service/external/ExternalPddGoodsLatestCommitStatusAppService.java
@@ -0,0 +1,12 @@
+package cn.qihangerp.service.external;
+
+import cn.qihangerp.model.request.ExternalPddGoodsLatestCommitStatusRequest;
+import cn.qihangerp.model.vo.ExternalPddGoodsDetailResultVo;
+
+/**
+ * 拼多多商品最新提交审核状态({@code pdd.goods.latest.commit.status.get}),薄封装,不做业务状态机。
+ */
+public interface ExternalPddGoodsLatestCommitStatusAppService {
+
+ ExternalPddGoodsDetailResultVo fetchLatestCommitStatus(ExternalPddGoodsLatestCommitStatusRequest req);
+}
diff --git a/service/src/main/java/cn/qihangerp/service/external/impl/ExternalPddGoodsLatestCommitStatusAppServiceImpl.java b/service/src/main/java/cn/qihangerp/service/external/impl/ExternalPddGoodsLatestCommitStatusAppServiceImpl.java
new file mode 100644
index 00000000..092c2606
--- /dev/null
+++ b/service/src/main/java/cn/qihangerp/service/external/impl/ExternalPddGoodsLatestCommitStatusAppServiceImpl.java
@@ -0,0 +1,110 @@
+package cn.qihangerp.service.external.impl;
+
+import cn.qihangerp.model.request.ExternalGoodsUpsertRequest;
+import cn.qihangerp.model.request.ExternalPddGoodsLatestCommitStatusRequest;
+import cn.qihangerp.model.vo.ExternalPddGoodsDetailResultVo;
+import cn.qihangerp.service.external.ExternalPddGoodsLatestCommitStatusAppService;
+import cn.qihangerp.service.external.pdd.ExternalPddProperties;
+import cn.qihangerp.service.external.pdd.PddOpenApiSupport;
+import cn.qihangerp.service.external.pdd.PddPopClient;
+import cn.qihangerp.service.external.shop.PddShopCredential;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+/**
+ * 仅调用 POP,返回原始 JSON 供主数据解析 {@code goods_latest_commit_status_get_response}。
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class ExternalPddGoodsLatestCommitStatusAppServiceImpl implements ExternalPddGoodsLatestCommitStatusAppService {
+
+ private final ExternalPddProperties props;
+ private final PddPopClient pddPopClient;
+
+ @Override
+ public ExternalPddGoodsDetailResultVo fetchLatestCommitStatus(ExternalPddGoodsLatestCommitStatusRequest req) {
+ if (req == null || CollectionUtils.isEmpty(req.getPddGoodsIds())) {
+ return ExternalPddGoodsDetailResultVo.builder()
+ .popBizSuccess(false)
+ .message("pddGoodsIds 不能为空")
+ .popResponseBody(null)
+ .build();
+ }
+ PddShopCredential cred = resolveCredential(req);
+ if (cred == null || !StringUtils.hasText(cred.getAppKey()) || !StringUtils.hasText(cred.getAppSecret())
+ || !StringUtils.hasText(cred.getAccessToken())) {
+ return ExternalPddGoodsDetailResultVo.builder()
+ .popBizSuccess(false)
+ .message("pddPopAuth 不完整:需 appKey、appSecret、accessToken")
+ .popResponseBody(null)
+ .build();
+ }
+ String gateway = StringUtils.hasText(cred.getGatewayUrl()) ? cred.getGatewayUrl() : props.getGatewayUrl();
+ if (!StringUtils.hasText(gateway)) {
+ return ExternalPddGoodsDetailResultVo.builder()
+ .popBizSuccess(false)
+ .message("未配置 POP gatewayUrl(请求体或 external.pdd.gateway-url)")
+ .popResponseBody(null)
+ .build();
+ }
+ List ids = req.getPddGoodsIds().stream().filter(id -> id != null && id > 0).toList();
+ if (ids.isEmpty()) {
+ return ExternalPddGoodsDetailResultVo.builder()
+ .popBizSuccess(false)
+ .message("pddGoodsIds 无有效正数")
+ .popResponseBody(null)
+ .build();
+ }
+ try {
+ String raw = pddPopClient.invokeTopLevelBiz(
+ gateway,
+ cred.getAppKey(),
+ cred.getAppSecret(),
+ cred.getAccessToken(),
+ "pdd.goods.latest.commit.status.get",
+ PddOpenApiSupport.goodsLatestCommitStatusGetTopLevelParams(ids));
+ boolean ok = !PddOpenApiSupport.isError(raw);
+ return ExternalPddGoodsDetailResultVo.builder()
+ .popBizSuccess(ok)
+ .message(ok ? "pdd.goods.latest.commit.status.get 调用成功" : ("pdd.goods.latest.commit.status.get 失败: " + PddOpenApiSupport.formatError(raw)))
+ .popResponseBody(raw)
+ .build();
+ } catch (Exception e) {
+ log.warn("[PDD] pdd.goods.latest.commit.status.get exception err={}", e.getMessage(), e);
+ return ExternalPddGoodsDetailResultVo.builder()
+ .popBizSuccess(false)
+ .message(e.getMessage())
+ .popResponseBody(null)
+ .build();
+ }
+ }
+
+ private static PddShopCredential resolveCredential(ExternalPddGoodsLatestCommitStatusRequest req) {
+ if (req == null || req.getPddPopAuth() == null) {
+ return null;
+ }
+ ExternalGoodsUpsertRequest.PddPopAuth a = req.getPddPopAuth();
+ PddShopCredential c = new PddShopCredential();
+ c.setAppKey(trimToNull(a.getAppKey()));
+ c.setAppSecret(trimToNull(a.getAppSecret()));
+ c.setAccessToken(trimToNull(a.getAccessToken()));
+ if (StringUtils.hasText(a.getGatewayUrl())) {
+ c.setGatewayUrl(a.getGatewayUrl().trim());
+ }
+ c.setSource("REQUEST");
+ return c;
+ }
+
+ private static String trimToNull(String s) {
+ if (!StringUtils.hasText(s)) {
+ return null;
+ }
+ return s.trim();
+ }
+}
diff --git a/service/src/main/java/cn/qihangerp/service/external/pdd/PddOpenApiSupport.java b/service/src/main/java/cn/qihangerp/service/external/pdd/PddOpenApiSupport.java
index b7e20430..19f1d1e0 100644
--- a/service/src/main/java/cn/qihangerp/service/external/pdd/PddOpenApiSupport.java
+++ b/service/src/main/java/cn/qihangerp/service/external/pdd/PddOpenApiSupport.java
@@ -51,6 +51,27 @@ public final class PddOpenApiSupport {
return m;
}
+ /**
+ * {@code pdd.goods.latest.commit.status.get}:与官方 POP 一致,业务参数在表单顶层;{@code goods_id_list} 为 JSON 数组字符串(如 {@code [123,456]})。
+ */
+ public static Map goodsLatestCommitStatusGetTopLevelParams(List goodsIds) {
+ if (goodsIds == null || goodsIds.isEmpty()) {
+ throw new IllegalArgumentException("goods_id_list 不能为空");
+ }
+ List sanitized = new ArrayList<>();
+ for (Long id : goodsIds) {
+ if (id != null && id > 0) {
+ sanitized.add(id);
+ }
+ }
+ if (sanitized.isEmpty()) {
+ throw new IllegalArgumentException("goods_id_list 无有效 goods_id");
+ }
+ Map m = new LinkedHashMap<>();
+ m.put("goods_id_list", JSON.toJSONString(sanitized));
+ return m;
+ }
+
/**
* {@code pdd.goods.quantity.update} 表单顶层参数(与 POP 官方 curl / Java SDK 一致:{@code goods_id}、{@code sku_id}、{@code quantity}、
* {@code update_type}、{@code force_update}、可选 {@code outer_id})。