feat(erp-open): add Weixin publish lane and platform rename
Introduce WEIXIN platform handling for external goods upsert with dedicated sphPopAuth validation and result fields, and add a placeholder Sph publish service behind external.sph.publish-enabled. Rename EnumShopType WEI to WEIXIN and update related references to keep internal channel behavior consistent. Made-with: Cursor
This commit is contained in:
parent
3b5ba130d5
commit
a4e3421a10
|
|
@ -13,6 +13,7 @@ import cn.qihangerp.erp.support.ExternalGoodsRequestLogSupport;
|
|||
import cn.qihangerp.service.external.ExternalGoodsAppService;
|
||||
import cn.qihangerp.service.external.ExternalGoodsPddQuantityUpdateAppService;
|
||||
import cn.qihangerp.service.external.pdd.ExternalPddProperties;
|
||||
import cn.qihangerp.service.external.sph.ExternalSphProperties;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -43,6 +44,7 @@ public class ExternalGoodsController extends BaseController {
|
|||
private final ExternalGoodsAppService externalGoodsAppService;
|
||||
private final ExternalGoodsPddQuantityUpdateAppService externalGoodsPddQuantityUpdateAppService;
|
||||
private final ExternalPddProperties externalPddProperties;
|
||||
private final ExternalSphProperties externalSphProperties;
|
||||
private final ExternalGoodsApiLogProperties goodsApiLogProperties;
|
||||
|
||||
@PostMapping("/upsert")
|
||||
|
|
@ -106,6 +108,17 @@ public class ExternalGoodsController extends BaseController {
|
|||
}
|
||||
}
|
||||
|
||||
if (EnumShopType.WEIXIN.equals(platform) && externalSphProperties.isPublishEnabled()) {
|
||||
if (req.getSphPopAuth() == null) {
|
||||
return AjaxResult.error("参数错误:开启微信视频号小店发布时 sphPopAuth 不能为空");
|
||||
}
|
||||
var sAuth = req.getSphPopAuth();
|
||||
if (!StringUtils.hasText(sAuth.getAppKey()) || !StringUtils.hasText(sAuth.getAppSecret())
|
||||
|| !StringUtils.hasText(sAuth.getAccessToken())) {
|
||||
return AjaxResult.error("参数错误:sphPopAuth 需提供 appKey、appSecret、accessToken");
|
||||
}
|
||||
}
|
||||
|
||||
ExternalGoodsUpsertResultVo vo = externalGoodsAppService.upsertGoods(req);
|
||||
log.info("[external/goods/upsert] response shopId={} outGoodsId={} erpGoodsId={} platform={}",
|
||||
req.getShopId(), req.getOutGoodsId(), vo.getGoodsId(), req.getPlatform());
|
||||
|
|
@ -115,6 +128,13 @@ public class ExternalGoodsController extends BaseController {
|
|||
vo.getPddPublishSuccess(),
|
||||
truncateLog(vo.getPddPublishMessage(), 800));
|
||||
}
|
||||
if (EnumShopType.WEIXIN.equals(platform)) {
|
||||
log.info("[external/goods/upsert] sphPublish attempted={} success={} message={} sphProductId={}",
|
||||
vo.getSphPublishAttempted(),
|
||||
vo.getSphPublishSuccess(),
|
||||
truncateLog(vo.getSphPublishMessage(), 800),
|
||||
vo.getSphProductId());
|
||||
}
|
||||
return AjaxResult.success(vo);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@
|
|||
// } else if (mqMessage.getShopType().getIndex() == EnumShopType.OFFLINE.getIndex()) {
|
||||
// log.info("订单消息OFFLINE");
|
||||
// orderService.offlineOrderMessage(mqMessage.getKeyId());
|
||||
// } else if (mqMessage.getShopType().getIndex() == EnumShopType.WEI.getIndex()) {
|
||||
// } else if (mqMessage.getShopType().getIndex() == EnumShopType.WEIXIN.getIndex()) {
|
||||
// log.info("订单消息WEI");
|
||||
// JSONObject jsonObject = openApiService.getWeiOrderDetail(mqMessage.getKeyId());
|
||||
// if (jsonObject.getInteger("code") != 200 || jsonObject.getJSONObject("data") == null) {
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
//
|
||||
// JSONObject refundDetail = jsonObject.getJSONObject("data");
|
||||
// refundService.douRefundMessage(mqMessage.getKeyId(), refundDetail);
|
||||
// } else if (mqMessage.getShopType().getIndex() == EnumShopType.WEI.getIndex()) {
|
||||
// } else if (mqMessage.getShopType().getIndex() == EnumShopType.WEIXIN.getIndex()) {
|
||||
// log.info("退款消息WEI");
|
||||
// JSONObject jsonObject = openApiService.getWeiRefundDetail(mqMessage.getKeyId());
|
||||
// if (jsonObject.getInteger("code") != 200 || jsonObject.getJSONObject("data") == null) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
// } else if(vo.getShopType().getIndex() == EnumShopType.DOU.getIndex()) {
|
||||
// logger.info("Kafka订单消息DOU"+vo.getKeyId());
|
||||
//// orderService.douOrderMessage(vo.getKeyId());
|
||||
// } else if(vo.getShopType().getIndex() == EnumShopType.WEI.getIndex()) {
|
||||
// } else if(vo.getShopType().getIndex() == EnumShopType.WEIXIN.getIndex()) {
|
||||
// logger.info("Kafka订单消息WEI"+vo.getKeyId());
|
||||
//// orderService.weiOrderMessage(vo.getKeyId());
|
||||
// }
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
// } else if(vo.getShopType().getIndex() == EnumShopType.DOU.getIndex()) {
|
||||
// logger.info("Kafka售后消息DOU"+vo.getKeyId());
|
||||
//// refundService.douRefundMessage(vo.getKeyId());
|
||||
// } else if(vo.getShopType().getIndex() == EnumShopType.WEI.getIndex()) {
|
||||
// } else if(vo.getShopType().getIndex() == EnumShopType.WEIXIN.getIndex()) {
|
||||
// logger.info("Kafka售后消息WEI"+vo.getKeyId());
|
||||
//// refundService.weiRefundMessage(vo.getKeyId());
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -77,6 +77,10 @@ public final class ExternalGoodsRequestLogSupport {
|
|||
if (auth != null && !auth.isEmpty()) {
|
||||
maskPddPopAuth(auth);
|
||||
}
|
||||
JSONObject sphAuth = root.getJSONObject("sphPopAuth");
|
||||
if (sphAuth != null && !sphAuth.isEmpty()) {
|
||||
maskPddPopAuth(sphAuth);
|
||||
}
|
||||
return root.toJSONString();
|
||||
} catch (Exception e) {
|
||||
return "{\"_logSanitizeError\":true}";
|
||||
|
|
|
|||
|
|
@ -77,4 +77,8 @@ external:
|
|||
DEFAULT: "303351846671360"
|
||||
sku-overrides: []
|
||||
|
||||
# 微信视频号小店(platform=WEIXIN):默认不调用渠道发品;接入 OpenAPI 后再开启
|
||||
sph:
|
||||
publish-enabled: false
|
||||
|
||||
# 说明:对外商品接口见 temp/yunxi-erp-open-goods-upsert-api.md;Nacos 对齐见 temp/erp-open-erp-api-nacos-yunxi-reference.md
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class WeiApiCommon {
|
|||
if (shop == null) {
|
||||
return ResultVo.error(HttpStatus.PARAMS_ERROR,"参数错误,没有找到店铺");
|
||||
}
|
||||
if (shop.getType() != EnumShopType.WEI.getIndex()) {
|
||||
if (shop.getType() != EnumShopType.WEIXIN.getIndex()) {
|
||||
return ResultVo.error(HttpStatus.PARAMS_ERROR, "参数错误,店铺不是微信小店店铺");
|
||||
}
|
||||
if(!StringUtils.hasText(shop.getAppKey())) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ public class WeiRefundController extends BaseController {
|
|||
// TODO:需要优化消息格式
|
||||
if(bo!=null && bo.getIds()!=null) {
|
||||
for(String id: bo.getIds()) {
|
||||
mqUtils.sendApiMessage(MqMessage.build(EnumShopType.WEI, MqType.REFUND_MESSAGE, id));
|
||||
mqUtils.sendApiMessage(MqMessage.build(EnumShopType.WEIXIN, MqType.REFUND_MESSAGE, id));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public enum EnumShopType {
|
|||
JDVC("京东自营", 280),
|
||||
PDD("拼多多", 300),
|
||||
DOU("抖店", 400),
|
||||
WEI("视频号", 500),
|
||||
WEIXIN("视频号", 500),
|
||||
KWAI("快手小店", 600),
|
||||
XHS("小红书", 700),
|
||||
OFFLINE("拼多多", 999)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
### 4.0 已确认口径(冻结)
|
||||
- `shopId`:**全平台唯一**,可直接作为本服务店铺主键,不考虑跨平台撞号。
|
||||
- `platform`:由外部系统显式传入,取值采用 **`PDD`/`TAO`/`JD`/`DOU`/`WEI`/`KWAI`/`XHS`**(后续平台新增再扩展枚举)。
|
||||
- `platform`:由外部系统显式传入,取值采用 **`PDD`/`TAO`/`JD`/`DOU`/`WEIXIN`/`KWAI`/`XHS`**(后续平台新增再扩展枚举)。
|
||||
- AK/SK:**一套即可**(外部系统作为单一调用方)。
|
||||
- `X-Timestamp`:**毫秒**(ms)。
|
||||
- `X-Signature`:**Base64** 编码(HMAC-SHA256 输出 bytes → Base64)。
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public class ExternalGoodsUpsertRequest {
|
|||
private Long shopId;
|
||||
|
||||
/**
|
||||
* 目标平台枚举:PDD/TAO/JD/DOU/WEI/KWAI/XHS(与 EnumShopType 命名一致)
|
||||
* 目标平台枚举:PDD/TAO/JD/DOU/WEIXIN/KWAI/XHS(与 EnumShopType 命名一致)
|
||||
*/
|
||||
private String platform;
|
||||
|
||||
|
|
@ -149,6 +149,12 @@ public class ExternalGoodsUpsertRequest {
|
|||
*/
|
||||
private PddPopAuth pddPopAuth;
|
||||
|
||||
/**
|
||||
* 微信视频号小店凭证(与 {@link PddPopAuth} 形态一致:appId/secret + 店铺 access_token)。
|
||||
* 当 {@code platform=WEIXIN}({@link cn.qihangerp.common.enums.EnumShopType#WEIXIN})且 {@code external.sph.publish-enabled=true} 时<b>必填</b>。
|
||||
*/
|
||||
private SphPopAuth sphPopAuth;
|
||||
|
||||
@Data
|
||||
public static class PddPopAuth {
|
||||
@JsonAlias({"app_key", "clientId", "client_id"})
|
||||
|
|
@ -165,6 +171,21 @@ public class ExternalGoodsUpsertRequest {
|
|||
private String gatewayUrl;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class SphPopAuth {
|
||||
@JsonAlias({"app_key", "clientId", "client_id"})
|
||||
private String appKey;
|
||||
|
||||
@JsonAlias({"app_secret", "clientSecret", "client_secret"})
|
||||
private String appSecret;
|
||||
|
||||
@JsonAlias({"access_token", "token", "sessionKey", "session_key"})
|
||||
private String accessToken;
|
||||
|
||||
@JsonAlias({"gateway_url", "channelsGatewayUrl"})
|
||||
private String gatewayUrl;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class AttributeItem {
|
||||
private String code;
|
||||
|
|
|
|||
|
|
@ -52,4 +52,19 @@ public class ExternalGoodsUpsertResultVo implements Serializable {
|
|||
/** 是否通过 spec.id.get 自动生成了 sku 规格 */
|
||||
private Boolean pddSpecAutoResolved;
|
||||
private String pddAutoResolveDetail;
|
||||
|
||||
// ---- 微信视频号小店(platform=WEIXIN)----
|
||||
|
||||
/** 是否尝试调用微信侧发品 */
|
||||
private Boolean sphPublishAttempted;
|
||||
|
||||
/** 微信发品是否成功(未尝试时为 null) */
|
||||
private Boolean sphPublishSuccess;
|
||||
|
||||
private String sphPublishMessage;
|
||||
|
||||
private String sphResponseSnippet;
|
||||
|
||||
/** 小店侧商品 ID(字符串) */
|
||||
private String sphProductId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package cn.qihangerp.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 微信视频号小店发品链路诊断(与 {@link PddPublishLaneResultVo} 对称,字段独立避免语义混淆)。
|
||||
*
|
||||
* @author guochengyu
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SphPublishLaneResultVo implements Serializable {
|
||||
|
||||
private Boolean attempted;
|
||||
private Boolean success;
|
||||
private String message;
|
||||
/** 渠道网关/适配层响应片段(脱敏前由服务端控制长度) */
|
||||
private String responseSnippet;
|
||||
/** 小店侧商品 ID(字符串,与微信返回形态一致) */
|
||||
private String sphProductId;
|
||||
}
|
||||
|
|
@ -210,7 +210,7 @@ public class WeiOrderServiceImpl extends ServiceImpl<WeiOrderMapper, WeiOrder>
|
|||
}
|
||||
OOrder order = new OOrder();
|
||||
order.setOrderNum(weiOrder.getOrderId());
|
||||
order.setShopType(EnumShopType.WEI.getIndex());
|
||||
order.setShopType(EnumShopType.WEIXIN.getIndex());
|
||||
order.setShopId(weiOrder.getShopId());
|
||||
// order.setShipType(confirmBo.getShipType());
|
||||
order.setShipType(0);
|
||||
|
|
@ -273,7 +273,7 @@ public class WeiOrderServiceImpl extends ServiceImpl<WeiOrderMapper, WeiOrder>
|
|||
oOrderItem.setOrderId(order.getId());
|
||||
oOrderItem.setOrderNum(order.getOrderNum());
|
||||
oOrderItem.setSubOrderNum(order.getOrderNum()+"-"+item.getSkuId());
|
||||
oOrderItem.setShopType(EnumShopType.WEI.getIndex());
|
||||
oOrderItem.setShopType(EnumShopType.WEIXIN.getIndex());
|
||||
oOrderItem.setShopId(weiOrder.getShopId());
|
||||
// 商品信息
|
||||
oOrderItem.setProductId(item.getProductId());
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import cn.qihangerp.model.request.ExternalGoodsDelistRequest;
|
|||
import cn.qihangerp.model.request.ExternalGoodsUpsertRequest;
|
||||
import cn.qihangerp.model.vo.ExternalGoodsUpsertResultVo;
|
||||
import cn.qihangerp.model.vo.PddPublishLaneResultVo;
|
||||
import cn.qihangerp.model.vo.SphPublishLaneResultVo;
|
||||
import cn.qihangerp.module.service.OGoodsService;
|
||||
import cn.qihangerp.module.service.OGoodsSkuService;
|
||||
import cn.qihangerp.service.external.ExternalGoodsAppService;
|
||||
import cn.qihangerp.service.external.pdd.ExternalPddPublishService;
|
||||
import cn.qihangerp.service.external.sph.ExternalSphPublishService;
|
||||
import cn.qihangerp.service.external.pdd.OGoodsPddMappingPersistence;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
|
|
@ -41,6 +43,7 @@ public class ExternalGoodsAppServiceImpl implements ExternalGoodsAppService {
|
|||
private final OGoodsService goodsService;
|
||||
private final OGoodsSkuService skuService;
|
||||
private final ExternalPddPublishService externalPddPublishService;
|
||||
private final ExternalSphPublishService externalSphPublishService;
|
||||
private final OGoodsPddMappingPersistence oGoodsPddMappingPersistence;
|
||||
|
||||
@Override
|
||||
|
|
@ -111,7 +114,12 @@ public class ExternalGoodsAppServiceImpl implements ExternalGoodsAppService {
|
|||
.pddCatRuleSnippet(null)
|
||||
.pddSpecAutoResolved(null)
|
||||
.pddAutoResolveDetail(null)
|
||||
.pddPublishLane(null);
|
||||
.pddPublishLane(null)
|
||||
.sphPublishAttempted(false)
|
||||
.sphPublishSuccess(null)
|
||||
.sphPublishMessage(null)
|
||||
.sphResponseSnippet(null)
|
||||
.sphProductId(null);
|
||||
|
||||
if ("PDD".equalsIgnoreCase(req.getPlatform())) {
|
||||
OGoods g = goodsService.getById(goodsId);
|
||||
|
|
@ -149,6 +157,36 @@ public class ExternalGoodsAppServiceImpl implements ExternalGoodsAppService {
|
|||
out.pddPublishLane(lane.getPublishLane());
|
||||
}
|
||||
|
||||
if ("WEIXIN".equalsIgnoreCase(req.getPlatform())) {
|
||||
OGoods g = goodsService.getById(goodsId);
|
||||
List<OGoodsSku> skuRows = skuService.list(new LambdaQueryWrapper<OGoodsSku>()
|
||||
.eq(OGoodsSku::getGoodsId, goodsId));
|
||||
Map<String, OGoodsSku> byOuter = new LinkedHashMap<>();
|
||||
for (OGoodsSku row : skuRows) {
|
||||
if (row != null && StringUtils.hasText(row.getOuterErpSkuId())) {
|
||||
byOuter.putIfAbsent(row.getOuterErpSkuId(), row);
|
||||
}
|
||||
}
|
||||
List<OGoodsSku> orderedSkus = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(req.getSkus())) {
|
||||
for (ExternalGoodsUpsertRequest.Sku sr : req.getSkus()) {
|
||||
if (sr == null || !StringUtils.hasText(sr.getOutSkuId())) {
|
||||
continue;
|
||||
}
|
||||
OGoodsSku row = byOuter.get(sr.getOutSkuId());
|
||||
if (row != null) {
|
||||
orderedSkus.add(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
SphPublishLaneResultVo lane = externalSphPublishService.publish(g, orderedSkus, req);
|
||||
out.sphPublishAttempted(Boolean.TRUE.equals(lane.getAttempted()));
|
||||
out.sphPublishSuccess(lane.getSuccess());
|
||||
out.sphPublishMessage(lane.getMessage());
|
||||
out.sphResponseSnippet(lane.getResponseSnippet());
|
||||
out.sphProductId(lane.getSphProductId());
|
||||
}
|
||||
|
||||
ExternalGoodsUpsertResultVo vo = out.build();
|
||||
if ("PDD".equalsIgnoreCase(req.getPlatform())) {
|
||||
oGoodsPddMappingPersistence.persistAfterPddPublishSuccess(goodsId, req, vo);
|
||||
|
|
@ -167,6 +205,16 @@ public class ExternalGoodsAppServiceImpl implements ExternalGoodsAppService {
|
|||
vo.getPddSpecAutoResolved(),
|
||||
truncateForLog(vo.getPddAutoResolveDetail(), 300));
|
||||
}
|
||||
if ("WEIXIN".equalsIgnoreCase(req.getPlatform())) {
|
||||
log.info("[external/upsert] WEIXIN summary shopId={} outGoodsId={} erpGoodsId={} attempted={} success={} message={} sphProductId={}",
|
||||
req.getShopId(),
|
||||
req.getOutGoodsId(),
|
||||
vo.getGoodsId(),
|
||||
vo.getSphPublishAttempted(),
|
||||
vo.getSphPublishSuccess(),
|
||||
truncateForLog(vo.getSphPublishMessage(), 600),
|
||||
vo.getSphProductId());
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
|
|
|
|||
12
service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphConfiguration.java
vendored
Normal file
12
service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphConfiguration.java
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package cn.qihangerp.service.external.sph;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author guochengyu
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ExternalSphProperties.class)
|
||||
public class ExternalSphConfiguration {
|
||||
}
|
||||
19
service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphProperties.java
vendored
Normal file
19
service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphProperties.java
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package cn.qihangerp.service.external.sph;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 微信视频号小店(platform=WEIXIN)发品相关开关;应用级密钥由调用方经 {@code sphPopAuth} 传入,与拼多多一致。
|
||||
*
|
||||
* @author guochengyu
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "external.sph")
|
||||
public class ExternalSphProperties {
|
||||
|
||||
/**
|
||||
* 是否在 upsert 落库后尝试调用微信小店发品适配(未接入前请保持 false,避免误报失败)。
|
||||
*/
|
||||
private boolean publishEnabled = false;
|
||||
}
|
||||
70
service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphPublishService.java
vendored
Normal file
70
service/src/main/java/cn/qihangerp/service/external/sph/ExternalSphPublishService.java
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package cn.qihangerp.service.external.sph;
|
||||
|
||||
import cn.qihangerp.model.entity.OGoods;
|
||||
import cn.qihangerp.model.entity.OGoodsSku;
|
||||
import cn.qihangerp.model.request.ExternalGoodsUpsertRequest;
|
||||
import cn.qihangerp.model.vo.SphPublishLaneResultVo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 微信视频号小店发品:凭证仅来自本次请求的 {@link ExternalGoodsUpsertRequest#getSphPopAuth()}。
|
||||
* <p>具体 HTTP/OpenAPI 接入在 {@code publishEnabled=true} 后实现;关闭开关时不调用渠道,与拼多多 {@link cn.qihangerp.service.external.pdd.ExternalPddPublishService} 行为对称。</p>
|
||||
*
|
||||
* @author guochengyu
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ExternalSphPublishService {
|
||||
|
||||
private final ExternalSphProperties props;
|
||||
|
||||
/**
|
||||
* 落库成功后可选调用微信侧发品;未开启或未实现时返回 {@code attempted=false},不阻断 ERP 本地 upsert。
|
||||
*/
|
||||
public SphPublishLaneResultVo publish(OGoods goods, List<OGoodsSku> skus, ExternalGoodsUpsertRequest req) {
|
||||
if (!props.isPublishEnabled()) {
|
||||
log.info("[SPH] publish skipped shopId={} outGoodsId={} reason=publish-disabled",
|
||||
req != null ? req.getShopId() : null,
|
||||
req != null ? req.getOutGoodsId() : null);
|
||||
return SphPublishLaneResultVo.builder()
|
||||
.attempted(false)
|
||||
.success(null)
|
||||
.message("external.sph.publish-enabled=false,未调用微信视频号小店")
|
||||
.build();
|
||||
}
|
||||
if (req == null) {
|
||||
return SphPublishLaneResultVo.builder()
|
||||
.attempted(false)
|
||||
.success(false)
|
||||
.message("请求参数不能为空")
|
||||
.build();
|
||||
}
|
||||
ExternalGoodsUpsertRequest.SphPopAuth auth = req.getSphPopAuth();
|
||||
if (auth == null || !StringUtils.hasText(auth.getAppKey()) || !StringUtils.hasText(auth.getAppSecret())
|
||||
|| !StringUtils.hasText(auth.getAccessToken())) {
|
||||
log.info("[SPH] publish skipped shopId={} outGoodsId={} reason=sphPopAuth-incomplete",
|
||||
req.getShopId(), req.getOutGoodsId());
|
||||
return SphPublishLaneResultVo.builder()
|
||||
.attempted(false)
|
||||
.success(false)
|
||||
.message("微信小店凭证不完整:请在请求体 sphPopAuth 中传入 appKey、appSecret、accessToken")
|
||||
.build();
|
||||
}
|
||||
// TODO: 接入微信视频号小店商品发布 OpenAPI,填充 sphProductId/responseSnippet
|
||||
log.warn("[SPH] publish-enabled=true 但发品适配尚未实现 shopId={} outGoodsId={} skuCount={}",
|
||||
req.getShopId(), req.getOutGoodsId(), skus == null ? 0 : skus.size());
|
||||
return SphPublishLaneResultVo.builder()
|
||||
.attempted(true)
|
||||
.success(false)
|
||||
.message("微信视频号小店发品接口尚未接入(请关闭 external.sph.publish-enabled 或完成适配开发)")
|
||||
.responseSnippet(null)
|
||||
.sphProductId(null)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue