拉取买家的卖家订单
This commit is contained in:
@@ -56,6 +56,9 @@ public class LbBuyerShoppingController {
|
|||||||
description =
|
description =
|
||||||
"按 tenantId 从 lb_third_integration_config 读取 login_api_path、buyer_order_list_path 等配置,"
|
"按 tenantId 从 lb_third_integration_config 读取 login_api_path、buyer_order_list_path 等配置,"
|
||||||
+ "对每个买方手机号模拟登录获取 token,再分页调用买方订单列表 API 并解析入库;"
|
+ "对每个买方手机号模拟登录获取 token,再分页调用买方订单列表 API 并解析入库;"
|
||||||
|
+ "拉取过程中将订单中的卖家手机号缓存到 cacheSellerPhones(已拉取过的号码不再缓存),"
|
||||||
|
+ "买方手机号全部处理完成后,仅对尚未拉取过的卖家手机号模拟登录、拉取订单并保存;"
|
||||||
|
+ "同一请求内重复手机号自动跳过,卖家阶段不再扩展缓存,避免重复拉取与死循环;"
|
||||||
+ "未传 password 时默认密码为 123456")
|
+ "未传 password 时默认密码为 123456")
|
||||||
public ResponseEntity<Map<String, Object>> pullFromThird(
|
public ResponseEntity<Map<String, Object>> pullFromThird(
|
||||||
@Parameter(description = "租户 id 与买方手机号列表", required = true)
|
@Parameter(description = "租户 id 与买方手机号列表", required = true)
|
||||||
|
|||||||
@@ -27,9 +27,11 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 买方购物表 lb_buyer_shopping 服务实现
|
* 买方购物表 lb_buyer_shopping 服务实现
|
||||||
@@ -340,16 +342,24 @@ public class LbBuyerShoppingServiceImpl
|
|||||||
}
|
}
|
||||||
HxrUserLoginApiContext loginCtx = loginCtxOpt.get();
|
HxrUserLoginApiContext loginCtx = loginCtxOpt.get();
|
||||||
|
|
||||||
|
Set<String> cacheSellerPhones = new LinkedHashSet<>();
|
||||||
|
Set<String> processedMobiles = new LinkedHashSet<>();
|
||||||
|
|
||||||
List<Map<String, Object>> items = new ArrayList<>();
|
List<Map<String, Object>> items = new ArrayList<>();
|
||||||
int successCount = 0;
|
int successCount = 0;
|
||||||
int failCount = 0;
|
int failCount = 0;
|
||||||
|
int skippedCount = 0;
|
||||||
int totalSaved = 0;
|
int totalSaved = 0;
|
||||||
int totalFetched = 0;
|
int totalFetched = 0;
|
||||||
String requestPassword = request.getPassword() != null ? request.getPassword().trim() : "";
|
String requestPassword = request.getPassword() != null ? request.getPassword().trim() : "";
|
||||||
|
String password = !requestPassword.isEmpty()
|
||||||
|
? requestPassword
|
||||||
|
: DEFAULT_SIMULATE_LOGIN_PASSWORD;
|
||||||
|
|
||||||
for (String rawMobile : request.getMobiles()) {
|
for (String rawMobile : request.getMobiles()) {
|
||||||
Map<String, Object> item = new LinkedHashMap<>();
|
String mobile = rawMobile != null ? rawMobile.trim() : "";
|
||||||
if (rawMobile == null || rawMobile.trim().isEmpty()) {
|
if (mobile.isEmpty()) {
|
||||||
|
Map<String, Object> item = new LinkedHashMap<>();
|
||||||
item.put("mobile", rawMobile);
|
item.put("mobile", rawMobile);
|
||||||
item.put("loginSuccess", false);
|
item.put("loginSuccess", false);
|
||||||
item.put("orderFetchSuccess", false);
|
item.put("orderFetchSuccess", false);
|
||||||
@@ -359,69 +369,58 @@ public class LbBuyerShoppingServiceImpl
|
|||||||
failCount++;
|
failCount++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (processedMobiles.contains(mobile)) {
|
||||||
|
Map<String, Object> item = buildSkippedPullItem(mobile, "手机号已拉取,跳过重复");
|
||||||
|
items.add(item);
|
||||||
|
skippedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
processedMobiles.add(mobile);
|
||||||
|
|
||||||
String mobile = rawMobile.trim();
|
Map<String, Object> item = pullOrdersForMobile(
|
||||||
item.put("mobile", mobile);
|
mobile, password, tenantId, loginCtx, cacheSellerPhones, processedMobiles);
|
||||||
String password = !requestPassword.isEmpty()
|
items.add(item);
|
||||||
? requestPassword
|
if (Boolean.TRUE.equals(item.get("orderFetchSuccess"))) {
|
||||||
: DEFAULT_SIMULATE_LOGIN_PASSWORD;
|
successCount++;
|
||||||
|
totalSaved += toInt(item.get("ordersSaved"));
|
||||||
try {
|
totalFetched += toInt(item.get("ordersFetched"));
|
||||||
HxrAdminUserLoginService.LoginApiResult loginResult =
|
} else {
|
||||||
hxrAdminUserLoginService.login(mobile, password, loginCtx);
|
|
||||||
item.put("httpStatus", loginResult.httpStatus());
|
|
||||||
item.put("apiCode", loginResult.apiCode());
|
|
||||||
item.put("apiMsg", loginResult.apiMsg());
|
|
||||||
item.put("loginSuccess", loginResult.success());
|
|
||||||
item.put("parsed", loginResult.parsed());
|
|
||||||
|
|
||||||
if (!loginResult.success()) {
|
|
||||||
item.put("orderFetchSuccess", false);
|
|
||||||
failCount++;
|
|
||||||
items.add(item);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String token = HxrAdminUserLoginService.extractToken(loginResult.parsed());
|
|
||||||
if (token == null || token.isBlank()) {
|
|
||||||
item.put("orderFetchSuccess", false);
|
|
||||||
item.put("orderFetchMsg", "响应中无 data.userinfo.token");
|
|
||||||
failCount++;
|
|
||||||
items.add(item);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Optional<HxrBuyerOrderApiContext> orderCtxOpt =
|
|
||||||
lbThirdIntegrationConfigService.resolveBuyerOrderApiContext(tenantId, token);
|
|
||||||
if (orderCtxOpt.isEmpty()) {
|
|
||||||
item.put("orderFetchSuccess", false);
|
|
||||||
item.put("orderFetchMsg",
|
|
||||||
"未找到买方订单 API 配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)");
|
|
||||||
failCount++;
|
|
||||||
items.add(item);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
HxrBuyerOrderApiContext orderCtx = orderCtxOpt.get();
|
|
||||||
item.put("buyerOrderListUrl", orderCtx.buyerOrderListBaseUrl());
|
|
||||||
|
|
||||||
Map<String, Object> fetchResult = fetchAndSaveBuyerOrders(orderCtx, mobile);
|
|
||||||
item.putAll(fetchResult);
|
|
||||||
if (Boolean.TRUE.equals(fetchResult.get("orderFetchSuccess"))) {
|
|
||||||
successCount++;
|
|
||||||
totalSaved += toInt(fetchResult.get("ordersSaved"));
|
|
||||||
totalFetched += toInt(fetchResult.get("ordersFetched"));
|
|
||||||
} else {
|
|
||||||
failCount++;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("买方购物第三方拉取异常 mobile={} tenantId={}", mobile, tenantId, e);
|
|
||||||
item.put("loginSuccess", false);
|
|
||||||
item.put("orderFetchSuccess", false);
|
|
||||||
item.put("apiCode", -1);
|
|
||||||
item.put("apiMsg", "请求异常:" + e.getMessage());
|
|
||||||
failCount++;
|
failCount++;
|
||||||
}
|
}
|
||||||
items.add(item);
|
}
|
||||||
|
|
||||||
|
List<String> sellerQueue = new ArrayList<>();
|
||||||
|
for (String sellerMobile : cacheSellerPhones) {
|
||||||
|
if (!processedMobiles.contains(sellerMobile)) {
|
||||||
|
sellerQueue.add(sellerMobile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, Object>> sellerItems = new ArrayList<>();
|
||||||
|
int sellerSuccessCount = 0;
|
||||||
|
int sellerFailCount = 0;
|
||||||
|
int sellerSkippedCount = 0;
|
||||||
|
int sellerTotalSaved = 0;
|
||||||
|
int sellerTotalFetched = 0;
|
||||||
|
for (String sellerMobile : sellerQueue) {
|
||||||
|
if (processedMobiles.contains(sellerMobile)) {
|
||||||
|
sellerItems.add(buildSkippedPullItem(sellerMobile, "卖家手机号已拉取,跳过重复"));
|
||||||
|
sellerSkippedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
processedMobiles.add(sellerMobile);
|
||||||
|
|
||||||
|
Map<String, Object> sellerItem = pullOrdersForMobile(
|
||||||
|
sellerMobile, password, tenantId, loginCtx, null, processedMobiles);
|
||||||
|
sellerItem.put("source", "cacheSellerPhones");
|
||||||
|
sellerItems.add(sellerItem);
|
||||||
|
if (Boolean.TRUE.equals(sellerItem.get("orderFetchSuccess"))) {
|
||||||
|
sellerSuccessCount++;
|
||||||
|
sellerTotalSaved += toInt(sellerItem.get("ordersSaved"));
|
||||||
|
sellerTotalFetched += toInt(sellerItem.get("ordersFetched"));
|
||||||
|
} else {
|
||||||
|
sellerFailCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.put("success", true);
|
result.put("success", true);
|
||||||
@@ -429,8 +428,18 @@ public class LbBuyerShoppingServiceImpl
|
|||||||
result.put("data", items);
|
result.put("data", items);
|
||||||
result.put("successCount", successCount);
|
result.put("successCount", successCount);
|
||||||
result.put("failCount", failCount);
|
result.put("failCount", failCount);
|
||||||
|
result.put("skippedCount", skippedCount);
|
||||||
result.put("ordersSaved", totalSaved);
|
result.put("ordersSaved", totalSaved);
|
||||||
result.put("ordersFetched", totalFetched);
|
result.put("ordersFetched", totalFetched);
|
||||||
|
result.put("cacheSellerPhones", new ArrayList<>(cacheSellerPhones));
|
||||||
|
result.put("sellerQueue", sellerQueue);
|
||||||
|
result.put("sellerData", sellerItems);
|
||||||
|
result.put("sellerSuccessCount", sellerSuccessCount);
|
||||||
|
result.put("sellerFailCount", sellerFailCount);
|
||||||
|
result.put("sellerSkippedCount", sellerSkippedCount);
|
||||||
|
result.put("sellerOrdersSaved", sellerTotalSaved);
|
||||||
|
result.put("sellerOrdersFetched", sellerTotalFetched);
|
||||||
|
result.put("processedMobiles", new ArrayList<>(processedMobiles));
|
||||||
result.put("loginApiUrl", loginCtx.loginApiUrl());
|
result.put("loginApiUrl", loginCtx.loginApiUrl());
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -441,7 +450,75 @@ public class LbBuyerShoppingServiceImpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> fetchAndSaveBuyerOrders(HxrBuyerOrderApiContext ctx, String buyerMobile) {
|
private Map<String, Object> buildSkippedPullItem(String mobile, String reason) {
|
||||||
|
Map<String, Object> item = new LinkedHashMap<>();
|
||||||
|
item.put("mobile", mobile);
|
||||||
|
item.put("skipped", true);
|
||||||
|
item.put("skipReason", reason);
|
||||||
|
item.put("loginSuccess", false);
|
||||||
|
item.put("orderFetchSuccess", false);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> pullOrdersForMobile(
|
||||||
|
String mobile,
|
||||||
|
String password,
|
||||||
|
String tenantId,
|
||||||
|
HxrUserLoginApiContext loginCtx,
|
||||||
|
Set<String> sellerPhoneCollector,
|
||||||
|
Set<String> processedMobiles) {
|
||||||
|
Map<String, Object> item = new LinkedHashMap<>();
|
||||||
|
item.put("mobile", mobile);
|
||||||
|
try {
|
||||||
|
HxrAdminUserLoginService.LoginApiResult loginResult =
|
||||||
|
hxrAdminUserLoginService.login(mobile, password, loginCtx);
|
||||||
|
item.put("httpStatus", loginResult.httpStatus());
|
||||||
|
item.put("apiCode", loginResult.apiCode());
|
||||||
|
item.put("apiMsg", loginResult.apiMsg());
|
||||||
|
item.put("loginSuccess", loginResult.success());
|
||||||
|
item.put("parsed", loginResult.parsed());
|
||||||
|
|
||||||
|
if (!loginResult.success()) {
|
||||||
|
item.put("orderFetchSuccess", false);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = HxrAdminUserLoginService.extractToken(loginResult.parsed());
|
||||||
|
if (token == null || token.isBlank()) {
|
||||||
|
item.put("orderFetchSuccess", false);
|
||||||
|
item.put("orderFetchMsg", "响应中无 data.userinfo.token");
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<HxrBuyerOrderApiContext> orderCtxOpt =
|
||||||
|
lbThirdIntegrationConfigService.resolveBuyerOrderApiContext(tenantId, token);
|
||||||
|
if (orderCtxOpt.isEmpty()) {
|
||||||
|
item.put("orderFetchSuccess", false);
|
||||||
|
item.put("orderFetchMsg",
|
||||||
|
"未找到买方订单 API 配置,或配置未启用、URL/凭证不完整(请检查 lb_third_integration_config)");
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
HxrBuyerOrderApiContext orderCtx = orderCtxOpt.get();
|
||||||
|
item.put("buyerOrderListUrl", orderCtx.buyerOrderListBaseUrl());
|
||||||
|
|
||||||
|
Map<String, Object> fetchResult =
|
||||||
|
fetchAndSaveBuyerOrders(orderCtx, mobile, sellerPhoneCollector, processedMobiles);
|
||||||
|
item.putAll(fetchResult);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("买方购物第三方拉取异常 mobile={} tenantId={}", mobile, tenantId, e);
|
||||||
|
item.put("loginSuccess", false);
|
||||||
|
item.put("orderFetchSuccess", false);
|
||||||
|
item.put("apiCode", -1);
|
||||||
|
item.put("apiMsg", "请求异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> fetchAndSaveBuyerOrders(
|
||||||
|
HxrBuyerOrderApiContext ctx,
|
||||||
|
String loginMobile,
|
||||||
|
Set<String> sellerPhoneCollector,
|
||||||
|
Set<String> processedMobiles) {
|
||||||
Map<String, Object> result = new LinkedHashMap<>();
|
Map<String, Object> result = new LinkedHashMap<>();
|
||||||
int page = 1;
|
int page = 1;
|
||||||
int totalSaved = 0;
|
int totalSaved = 0;
|
||||||
@@ -495,8 +572,9 @@ public class LbBuyerShoppingServiceImpl
|
|||||||
if (entity.getId() == null) {
|
if (entity.getId() == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
collectSellerPhone(entity, sellerPhoneCollector, processedMobiles);
|
||||||
if (entity.getBuyerMobile() == null || entity.getBuyerMobile().isBlank()) {
|
if (entity.getBuyerMobile() == null || entity.getBuyerMobile().isBlank()) {
|
||||||
entity.setBuyerMobile(buyerMobile);
|
entity.setBuyerMobile(loginMobile);
|
||||||
}
|
}
|
||||||
applyDefaults(entity);
|
applyDefaults(entity);
|
||||||
if (entity.getCreatedAt() == null) {
|
if (entity.getCreatedAt() == null) {
|
||||||
@@ -539,7 +617,7 @@ public class LbBuyerShoppingServiceImpl
|
|||||||
result.put("orderPages", page);
|
result.put("orderPages", page);
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("拉取买方订单异常 buyerMobile={}", buyerMobile, e);
|
log.warn("拉取买方订单异常 loginMobile={}", loginMobile, e);
|
||||||
result.put("orderFetchSuccess", false);
|
result.put("orderFetchSuccess", false);
|
||||||
result.put("orderFetchMsg", "拉取买方订单异常:" + e.getMessage());
|
result.put("orderFetchMsg", "拉取买方订单异常:" + e.getMessage());
|
||||||
result.put("ordersSaved", totalSaved);
|
result.put("ordersSaved", totalSaved);
|
||||||
@@ -791,6 +869,22 @@ public class LbBuyerShoppingServiceImpl
|
|||||||
private record StatAggregate(BigDecimal totalMoney, int orderCount, BigDecimal avgAmount) {
|
private record StatAggregate(BigDecimal totalMoney, int orderCount, BigDecimal avgAmount) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void collectSellerPhone(
|
||||||
|
LbBuyerShopping entity, Set<String> collector, Set<String> processedMobiles) {
|
||||||
|
if (collector == null || entity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String phone = entity.getSellerMobile();
|
||||||
|
if (phone == null || phone.isBlank()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String trimmed = phone.trim();
|
||||||
|
if (processedMobiles != null && processedMobiles.contains(trimmed)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collector.add(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
private static int toInt(Object value) {
|
private static int toInt(Object value) {
|
||||||
if (value instanceof Number number) {
|
if (value instanceof Number number) {
|
||||||
return number.intValue();
|
return number.intValue();
|
||||||
|
|||||||
Reference in New Issue
Block a user