1
This commit is contained in:
@@ -69,5 +69,39 @@ public interface IErpProductService
|
||||
* @return 拉取结果
|
||||
*/
|
||||
public int pullAndSaveProductList(String appid, Integer pageNo, Integer pageSize, Integer productStatus);
|
||||
|
||||
/**
|
||||
* 全量同步商品列表(自动遍历所有页码,同步更新和删除)
|
||||
*
|
||||
* @param appid ERP应用ID
|
||||
* @param productStatus 商品状态(null表示全部状态)
|
||||
* @return 同步结果
|
||||
*/
|
||||
public SyncResult syncAllProducts(String appid, Integer productStatus);
|
||||
|
||||
/**
|
||||
* 同步结果
|
||||
*/
|
||||
public static class SyncResult {
|
||||
private int totalPulled; // 拉取总数
|
||||
private int added; // 新增数量
|
||||
private int updated; // 更新数量
|
||||
private int deleted; // 删除数量
|
||||
private int failed; // 失败数量
|
||||
private String message; // 结果消息
|
||||
|
||||
public int getTotalPulled() { return totalPulled; }
|
||||
public void setTotalPulled(int totalPulled) { this.totalPulled = totalPulled; }
|
||||
public int getAdded() { return added; }
|
||||
public void setAdded(int added) { this.added = added; }
|
||||
public int getUpdated() { return updated; }
|
||||
public void setUpdated(int updated) { this.updated = updated; }
|
||||
public int getDeleted() { return deleted; }
|
||||
public void setDeleted(int deleted) { this.deleted = deleted; }
|
||||
public int getFailed() { return failed; }
|
||||
public void setFailed(int failed) { this.failed = failed; }
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,14 @@ import com.ruoyi.jarvis.domain.ErpProduct;
|
||||
import com.ruoyi.jarvis.service.IErpProductService;
|
||||
import com.ruoyi.erp.request.ERPAccount;
|
||||
import com.ruoyi.erp.request.ProductListQueryRequest;
|
||||
import com.ruoyi.erp.request.ProductDeleteRequest;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 闲鱼商品Service业务层处理
|
||||
@@ -313,6 +317,164 @@ public class ErpProductServiceImpl implements IErpProductService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量同步商品列表(自动遍历所有页码,同步更新和删除)
|
||||
*/
|
||||
@Override
|
||||
public IErpProductService.SyncResult syncAllProducts(String appid, Integer productStatus) {
|
||||
IErpProductService.SyncResult result = new IErpProductService.SyncResult();
|
||||
Set<Long> remoteProductIds = new HashSet<>(); // 远程商品ID集合
|
||||
int pageNo = 1;
|
||||
int pageSize = 50; // 每页50条,尽量少请求次数
|
||||
int totalPulled = 0;
|
||||
int added = 0;
|
||||
int updated = 0;
|
||||
|
||||
try {
|
||||
ERPAccount account = resolveAccount(appid);
|
||||
|
||||
// 第一步:遍历所有页码,拉取并保存所有商品
|
||||
log.info("开始全量同步商品,账号:{}", appid);
|
||||
while (true) {
|
||||
ProductListQueryRequest request = new ProductListQueryRequest(account);
|
||||
request.setPage(pageNo, pageSize);
|
||||
|
||||
if (productStatus != null) {
|
||||
Integer apiStatus = convertProductStatus(productStatus);
|
||||
if (apiStatus != null) {
|
||||
request.setProductStatus(apiStatus);
|
||||
}
|
||||
}
|
||||
|
||||
String responseBody = request.getResponseBody();
|
||||
JSONObject response = JSONObject.parseObject(responseBody);
|
||||
|
||||
if (response == null || response.getInteger("code") == null || response.getInteger("code") != 0) {
|
||||
String errorMsg = response != null ? response.getString("msg") : "未知错误";
|
||||
log.error("拉取商品列表失败(页码:{}): {}", pageNo, errorMsg);
|
||||
result.setFailed(result.getFailed() + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
JSONObject data = response.getJSONObject("data");
|
||||
if (data == null) {
|
||||
log.warn("拉取商品列表返回数据为空(页码:{})", pageNo);
|
||||
break;
|
||||
}
|
||||
|
||||
JSONArray productList = data.getJSONArray("list");
|
||||
|
||||
if (productList == null || productList.isEmpty()) {
|
||||
log.info("第 {} 页数据为空,同步完成", pageNo);
|
||||
break;
|
||||
}
|
||||
|
||||
// 处理当前页商品
|
||||
for (int i = 0; i < productList.size(); i++) {
|
||||
JSONObject productJson = productList.getJSONObject(i);
|
||||
ErpProduct erpProduct = parseProductJson(productJson, appid);
|
||||
if (erpProduct != null && erpProduct.getProductId() != null) {
|
||||
remoteProductIds.add(erpProduct.getProductId());
|
||||
|
||||
// 保存或更新商品
|
||||
ErpProduct existing = erpProductMapper.selectErpProductByProductIdAndAppid(
|
||||
erpProduct.getProductId(), erpProduct.getAppid());
|
||||
if (existing != null) {
|
||||
erpProduct.setId(existing.getId());
|
||||
erpProductMapper.updateErpProduct(erpProduct);
|
||||
updated++;
|
||||
} else {
|
||||
erpProductMapper.insertErpProduct(erpProduct);
|
||||
added++;
|
||||
}
|
||||
totalPulled++;
|
||||
}
|
||||
}
|
||||
|
||||
log.info("已同步第 {} 页,共 {} 条商品", pageNo, productList.size());
|
||||
|
||||
// 判断是否还有下一页
|
||||
if (productList.size() < pageSize) {
|
||||
log.info("已拉取完所有页码,共 {} 页", pageNo);
|
||||
break;
|
||||
}
|
||||
|
||||
pageNo++;
|
||||
}
|
||||
|
||||
result.setTotalPulled(totalPulled);
|
||||
result.setAdded(added);
|
||||
result.setUpdated(updated);
|
||||
|
||||
// 第二步:对比本地和远程,删除本地有但远程没有的商品
|
||||
log.info("开始同步删除,远程商品数:{}", remoteProductIds.size());
|
||||
|
||||
// 查询本地该账号下的所有商品
|
||||
ErpProduct queryParam = new ErpProduct();
|
||||
queryParam.setAppid(appid);
|
||||
List<ErpProduct> localProducts = erpProductMapper.selectErpProductList(queryParam);
|
||||
|
||||
// 找出需要删除的商品(本地有但远程没有的)
|
||||
List<ErpProduct> toDelete = localProducts.stream()
|
||||
.filter(p -> !remoteProductIds.contains(p.getProductId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!toDelete.isEmpty()) {
|
||||
log.info("发现 {} 个本地商品在远程已不存在,开始删除", toDelete.size());
|
||||
|
||||
for (ErpProduct product : toDelete) {
|
||||
try {
|
||||
// 先调用远程删除接口
|
||||
ProductDeleteRequest deleteRequest = new ProductDeleteRequest(account);
|
||||
deleteRequest.setProductId(product.getProductId());
|
||||
String deleteResponse = deleteRequest.getResponseBody();
|
||||
JSONObject deleteResult = JSONObject.parseObject(deleteResponse);
|
||||
|
||||
if (deleteResult != null && deleteResult.getInteger("code") != null &&
|
||||
deleteResult.getInteger("code") == 0) {
|
||||
// 远程删除成功,删除本地记录
|
||||
erpProductMapper.deleteErpProductById(product.getId());
|
||||
result.setDeleted(result.getDeleted() + 1);
|
||||
log.debug("成功删除商品:{}", product.getProductId());
|
||||
} else {
|
||||
// 远程删除失败,记录日志但不删除本地(可能是远程已经删除了)
|
||||
String errorMsg = deleteResult != null ? deleteResult.getString("msg") : "未知错误";
|
||||
log.warn("远程删除商品失败(可能已不存在):{},错误:{}", product.getProductId(), errorMsg);
|
||||
// 如果远程返回商品不存在的错误,也删除本地记录
|
||||
if (errorMsg != null && (errorMsg.contains("不存在") || errorMsg.contains("not found"))) {
|
||||
erpProductMapper.deleteErpProductById(product.getId());
|
||||
result.setDeleted(result.getDeleted() + 1);
|
||||
} else {
|
||||
result.setFailed(result.getFailed() + 1);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("删除商品异常:{}", product.getProductId(), e);
|
||||
result.setFailed(result.getFailed() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 构建结果消息
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append(String.format("同步完成!拉取:%d个,新增:%d个,更新:%d个,删除:%d个",
|
||||
totalPulled, added, updated, result.getDeleted()));
|
||||
if (result.getFailed() > 0) {
|
||||
msg.append(String.format(",失败:%d个", result.getFailed()));
|
||||
}
|
||||
result.setMessage(msg.toString());
|
||||
|
||||
log.info(result.getMessage());
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("全量同步商品异常", e);
|
||||
result.setMessage("同步失败: " + e.getMessage());
|
||||
result.setFailed(result.getFailed() + 1);
|
||||
throw new RuntimeException("全量同步商品失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析ERP账号
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user