feat(pdd): 新增 sku-canonical-sync 接口供主数据回写 pddSkuId
主数据在 detail.get 成功后回调,将 POP sku_list 映射合并写入 o_goods_sku.canonical_ext。 Made-with: Cursor
This commit is contained in:
parent
03a45c3eb4
commit
3b5ba130d5
|
|
@ -3,12 +3,15 @@ package cn.qihangerp.erp.controller;
|
||||||
import cn.qihangerp.common.AjaxResult;
|
import cn.qihangerp.common.AjaxResult;
|
||||||
import cn.qihangerp.model.request.ExternalPddGoodsDetailRequest;
|
import cn.qihangerp.model.request.ExternalPddGoodsDetailRequest;
|
||||||
import cn.qihangerp.model.request.ExternalPddGoodsLatestCommitStatusRequest;
|
import cn.qihangerp.model.request.ExternalPddGoodsLatestCommitStatusRequest;
|
||||||
|
import cn.qihangerp.model.request.ExternalPddSkuCanonicalSyncRequest;
|
||||||
import cn.qihangerp.model.vo.ExternalPddGoodsDetailResultVo;
|
import cn.qihangerp.model.vo.ExternalPddGoodsDetailResultVo;
|
||||||
|
import cn.qihangerp.model.vo.ExternalPddSkuCanonicalSyncResultVo;
|
||||||
import cn.qihangerp.security.common.BaseController;
|
import cn.qihangerp.security.common.BaseController;
|
||||||
import cn.qihangerp.erp.config.ExternalGoodsApiLogProperties;
|
import cn.qihangerp.erp.config.ExternalGoodsApiLogProperties;
|
||||||
import cn.qihangerp.erp.support.ExternalGoodsRequestLogSupport;
|
import cn.qihangerp.erp.support.ExternalGoodsRequestLogSupport;
|
||||||
import cn.qihangerp.service.external.ExternalPddGoodsDetailAppService;
|
import cn.qihangerp.service.external.ExternalPddGoodsDetailAppService;
|
||||||
import cn.qihangerp.service.external.ExternalPddGoodsLatestCommitStatusAppService;
|
import cn.qihangerp.service.external.ExternalPddGoodsLatestCommitStatusAppService;
|
||||||
|
import cn.qihangerp.service.external.ExternalPddSkuCanonicalSyncAppService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
@ -22,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@code POST /external/pdd/goods/detail} — {@code pdd.goods.detail.get}</li>
|
* <li>{@code POST /external/pdd/goods/detail} — {@code pdd.goods.detail.get}</li>
|
||||||
* <li>{@code POST /external/pdd/goods/latest-commit-status} — {@code pdd.goods.latest.commit.status.get}</li>
|
* <li>{@code POST /external/pdd/goods/latest-commit-status} — {@code pdd.goods.latest.commit.status.get}</li>
|
||||||
|
* <li>{@code POST /external/pdd/goods/sku-canonical-sync} — 主数据在 detail 成功后回写 {@code o_goods_sku.canonical_ext.pddSkuId}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p>改库存请使用 {@code POST /external/goods/pdd/quantity/update}(与 upsert 相同 out 键)。</p>
|
* <p>改库存请使用 {@code POST /external/goods/pdd/quantity/update}(与 upsert 相同 out 键)。</p>
|
||||||
*/
|
*/
|
||||||
|
|
@ -33,6 +37,7 @@ public class ExternalPddGoodsController extends BaseController {
|
||||||
|
|
||||||
private final ExternalPddGoodsDetailAppService externalPddGoodsDetailAppService;
|
private final ExternalPddGoodsDetailAppService externalPddGoodsDetailAppService;
|
||||||
private final ExternalPddGoodsLatestCommitStatusAppService externalPddGoodsLatestCommitStatusAppService;
|
private final ExternalPddGoodsLatestCommitStatusAppService externalPddGoodsLatestCommitStatusAppService;
|
||||||
|
private final ExternalPddSkuCanonicalSyncAppService externalPddSkuCanonicalSyncAppService;
|
||||||
private final ExternalGoodsApiLogProperties goodsApiLogProperties;
|
private final ExternalGoodsApiLogProperties goodsApiLogProperties;
|
||||||
|
|
||||||
@PostMapping("/detail")
|
@PostMapping("/detail")
|
||||||
|
|
@ -76,9 +81,32 @@ public class ExternalPddGoodsController extends BaseController {
|
||||||
return AjaxResult.error("参数错误:pddPopAuth 需提供 appKey、appSecret、accessToken");
|
return AjaxResult.error("参数错误:pddPopAuth 需提供 appKey、appSecret、accessToken");
|
||||||
}
|
}
|
||||||
ExternalPddGoodsDetailResultVo vo = externalPddGoodsLatestCommitStatusAppService.fetchLatestCommitStatus(req);
|
ExternalPddGoodsDetailResultVo vo = externalPddGoodsLatestCommitStatusAppService.fetchLatestCommitStatus(req);
|
||||||
|
int n = req.getPddGoodsIds().size();
|
||||||
|
log.info(
|
||||||
|
"[external/pdd/goods/latest-commit-status] goodsIdCount={} popBizSuccess={} msg={}",
|
||||||
|
n,
|
||||||
|
vo.getPopBizSuccess(),
|
||||||
|
vo.getMessage());
|
||||||
if (!Boolean.TRUE.equals(vo.getPopBizSuccess())) {
|
if (!Boolean.TRUE.equals(vo.getPopBizSuccess())) {
|
||||||
return AjaxResult.error(StringUtils.hasText(vo.getMessage()) ? vo.getMessage() : "pdd.goods.latest.commit.status.get 失败");
|
return AjaxResult.error(StringUtils.hasText(vo.getMessage()) ? vo.getMessage() : "pdd.goods.latest.commit.status.get 失败");
|
||||||
}
|
}
|
||||||
return AjaxResult.success(vo);
|
return AjaxResult.success(vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/sku-canonical-sync")
|
||||||
|
public AjaxResult skuCanonicalSync(@RequestBody ExternalPddSkuCanonicalSyncRequest req) {
|
||||||
|
if (goodsApiLogProperties.isLogFullRequest()) {
|
||||||
|
int rawLen = req != null && req.getGoodsDetailPopRaw() != null ? req.getGoodsDetailPopRaw().length() : 0;
|
||||||
|
log.info("[external/pdd/goods/sku-canonical-sync] erpGoodsId={} goodsDetailPopRawLen={}",
|
||||||
|
req != null ? req.getErpGoodsId() : null, rawLen);
|
||||||
|
}
|
||||||
|
if (req == null || req.getErpGoodsId() == null || req.getErpGoodsId() <= 0) {
|
||||||
|
return AjaxResult.error("参数错误:erpGoodsId 不能为空且须为正数");
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(req.getGoodsDetailPopRaw())) {
|
||||||
|
return AjaxResult.error("参数错误:goodsDetailPopRaw 不能为空");
|
||||||
|
}
|
||||||
|
ExternalPddSkuCanonicalSyncResultVo vo = externalPddSkuCanonicalSyncAppService.syncFromGoodsDetailPop(req);
|
||||||
|
return AjaxResult.success(vo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package cn.qihangerp.model.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code POST /external/pdd/goods/sku-canonical-sync}:主数据在 {@code detail.get} 成功后回写
|
||||||
|
* {@code o_goods_sku.canonical_ext.pddSkuId}。
|
||||||
|
* <p>与 {@link ExternalPddGoodsDetailAppService#fetchGoodsDetail} 返回的 {@code popResponseBody} 同源(拼多多 POP 原始 JSON,
|
||||||
|
* 须含 {@code goods_detail_get_response.sku_list})。</p>
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ExternalPddSkuCanonicalSyncRequest {
|
||||||
|
|
||||||
|
/** ERP {@code o_goods.id} */
|
||||||
|
private Long erpGoodsId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code pdd.goods.detail.get} 成功响应原始 JSON(顶层含 {@code goods_detail_get_response})。
|
||||||
|
*/
|
||||||
|
private String goodsDetailPopRaw;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package cn.qihangerp.model.vo;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code /external/pdd/goods/sku-canonical-sync} 业务结果。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ExternalPddSkuCanonicalSyncResultVo implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 实际更新了 {@code canonical_ext} 的 SKU 行数 */
|
||||||
|
private int updatedSkuRows;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
}
|
||||||
12
service/src/main/java/cn/qihangerp/service/external/ExternalPddSkuCanonicalSyncAppService.java
vendored
Normal file
12
service/src/main/java/cn/qihangerp/service/external/ExternalPddSkuCanonicalSyncAppService.java
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
package cn.qihangerp.service.external;
|
||||||
|
|
||||||
|
import cn.qihangerp.model.request.ExternalPddSkuCanonicalSyncRequest;
|
||||||
|
import cn.qihangerp.model.vo.ExternalPddSkuCanonicalSyncResultVo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主数据回调:将 {@code detail.get} 中的 SKU 映射写入 {@code o_goods_sku.canonical_ext}。
|
||||||
|
*/
|
||||||
|
public interface ExternalPddSkuCanonicalSyncAppService {
|
||||||
|
|
||||||
|
ExternalPddSkuCanonicalSyncResultVo syncFromGoodsDetailPop(ExternalPddSkuCanonicalSyncRequest req);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package cn.qihangerp.service.external.impl;
|
||||||
|
|
||||||
|
import cn.qihangerp.model.entity.OGoods;
|
||||||
|
import cn.qihangerp.model.request.ExternalPddSkuCanonicalSyncRequest;
|
||||||
|
import cn.qihangerp.model.vo.ExternalPddSkuCanonicalSyncResultVo;
|
||||||
|
import cn.qihangerp.module.service.OGoodsService;
|
||||||
|
import cn.qihangerp.service.external.ExternalPddSkuCanonicalSyncAppService;
|
||||||
|
import cn.qihangerp.service.external.pdd.OGoodsPddMappingPersistence;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
/**
|
||||||
|
* @author guochengyu
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ExternalPddSkuCanonicalSyncAppServiceImpl implements ExternalPddSkuCanonicalSyncAppService {
|
||||||
|
|
||||||
|
private final OGoodsService goodsService;
|
||||||
|
private final OGoodsPddMappingPersistence oGoodsPddMappingPersistence;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExternalPddSkuCanonicalSyncResultVo syncFromGoodsDetailPop(ExternalPddSkuCanonicalSyncRequest req) {
|
||||||
|
OGoods g = goodsService.getById(req.getErpGoodsId());
|
||||||
|
if (g == null) {
|
||||||
|
return ExternalPddSkuCanonicalSyncResultVo.builder()
|
||||||
|
.updatedSkuRows(0)
|
||||||
|
.message("o_goods 不存在: " + req.getErpGoodsId())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
int n = oGoodsPddMappingPersistence.mergePddSkuCanonicalFromGoodsDetailPop(
|
||||||
|
req.getErpGoodsId(), req.getGoodsDetailPopRaw().trim());
|
||||||
|
return ExternalPddSkuCanonicalSyncResultVo.builder()
|
||||||
|
.updatedSkuRows(n)
|
||||||
|
.message(n > 0 ? "已合并 pddSkuId" : "无匹配 outerErpSkuId 或未解析到 sku_list")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -26,7 +26,8 @@ import java.util.Map;
|
||||||
*
|
*
|
||||||
* <p>拼多多:仅根据 {@code pdd.goods.add} 成功响应中的 {@code sku_list} 回填 {@value #CANONICAL_PDD_SKU_ID};<strong>不在本服务内</strong>调用
|
* <p>拼多多:仅根据 {@code pdd.goods.add} 成功响应中的 {@code sku_list} 回填 {@value #CANONICAL_PDD_SKU_ID};<strong>不在本服务内</strong>调用
|
||||||
* {@code pdd.goods.detail.get}。{@code pdd.goods.information.update} 若未带 {@code sku_list},则 {@code pddSkuId} 须由主数据在适当时机
|
* {@code pdd.goods.detail.get}。{@code pdd.goods.information.update} 若未带 {@code sku_list},则 {@code pddSkuId} 须由主数据在适当时机
|
||||||
* 调 {@code POST /external/pdd/goods/detail} 后自行落库或后续扩展同步接口写回 ERP(当前 detail 接口仅返回 JSON 给调用方)。</p>
|
* 调 {@code POST /external/pdd/goods/detail} 成功后,由主数据再调 {@code POST /external/pdd/goods/sku-canonical-sync} 将
|
||||||
|
* {@code sku_list} 映射合并写入 {@code o_goods_sku.canonical_ext}(键 {@value #CANONICAL_PDD_SKU_ID})。</p>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -78,6 +79,21 @@ public class OGoodsPddMappingPersistence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 {@code pdd.goods.detail.get} 的 POP 原始 JSON 解析 {@code sku_list},按 {@code outerErpSkuId} 合并写入
|
||||||
|
* {@code o_goods_sku.canonicalExt.pddSkuId}(与 {@link #persistAfterPddPublishSuccess} 中 GOODS_ADD 片段逻辑一致)。
|
||||||
|
*
|
||||||
|
* @return 实际更新行数
|
||||||
|
*/
|
||||||
|
public int mergePddSkuCanonicalFromGoodsDetailPop(Long erpGoodsId, String goodsDetailPopRaw) {
|
||||||
|
if (erpGoodsId == null || erpGoodsId <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Map<String, Long> outerToPddSku =
|
||||||
|
PddOpenApiSupport.parseOuterKeyToPddSkuIdFromGoodsDetailGetResponse(goodsDetailPopRaw);
|
||||||
|
return applyPddSkuMappings(erpGoodsId, outerToPddSku);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 {@code outerKey -> 拼多多 sku_id} 合并写入 {@code o_goods_sku.canonicalExt}(键 {@value #CANONICAL_PDD_SKU_ID})。
|
* 将 {@code outerKey -> 拼多多 sku_id} 合并写入 {@code o_goods_sku.canonicalExt}(键 {@value #CANONICAL_PDD_SKU_ID})。
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue