1
This commit is contained in:
@@ -17,7 +17,7 @@ public class JarvisGoofishProperties {
|
||||
|
||||
private String consumerGroup = "jarvis-goofish-order-consumer";
|
||||
|
||||
/** 回溯拉单小时数 */
|
||||
/** 回溯拉单小时数(定时/增量) */
|
||||
private int pullLookbackHours = 72;
|
||||
|
||||
/** 拉单定时 cron */
|
||||
@@ -26,8 +26,25 @@ public class JarvisGoofishProperties {
|
||||
/** 同步运单 + 自动发货 cron */
|
||||
private String autoShipCron = "0 2/10 * * * ?";
|
||||
|
||||
/** 单次拉单每店最大页数防护 */
|
||||
private int pullMaxPagesPerShop = 30;
|
||||
/**
|
||||
* 订单列表 page_size(开放平台最大 100)
|
||||
*/
|
||||
private int pullPageSize = 100;
|
||||
|
||||
/**
|
||||
* 单次拉单每授权最大页数(开放平台 page_no 最大 100;page_no×page_size 勿超过 10000)
|
||||
*/
|
||||
private int pullMaxPagesPerShop = 100;
|
||||
|
||||
/**
|
||||
* 全量/长历史拉单时,按 update_time 切片的窗口长度(秒),避免单窗内订单量过大触发平台限制
|
||||
*/
|
||||
private int pullTimeChunkSeconds = 604800;
|
||||
|
||||
/**
|
||||
* 全量拉单从「当前时间」往前推多少天作为起点(仅 full 接口;可自行改大)
|
||||
*/
|
||||
private int pullFullHistoryDays = 1095;
|
||||
|
||||
private int autoShipBatchSize = 20;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,27 @@ public class ErpGoofishOrder {
|
||||
private Long modifyTime;
|
||||
private Long productId;
|
||||
private Long itemId;
|
||||
/** 详情 goods.title */
|
||||
private String goodsTitle;
|
||||
/** goods.images 首张或其它单图字段 */
|
||||
private String goodsImageUrl;
|
||||
private String buyerNick;
|
||||
/** 开放平台 pay_amount,单位:分 */
|
||||
private Long payAmount;
|
||||
/** 闲管家详情 waybill_no */
|
||||
private String detailWaybillNo;
|
||||
private String detailExpressCode;
|
||||
private String detailExpressName;
|
||||
private String receiverName;
|
||||
private String receiverMobile;
|
||||
private String receiverAddress;
|
||||
/** 省市区拼接 */
|
||||
private String receiverRegion;
|
||||
/** 待发货等状态下开放平台返回的分级地址(与 prov_name/city_name/area_name/town_name 一致) */
|
||||
private String recvProvName;
|
||||
private String recvCityName;
|
||||
private String recvAreaName;
|
||||
private String recvTownName;
|
||||
private String detailJson;
|
||||
private String lastNotifyJson;
|
||||
private Long jdOrderId;
|
||||
@@ -41,4 +62,6 @@ public class ErpGoofishOrder {
|
||||
private String jdThirdPartyOrderNo;
|
||||
/** 联查:内部备注单号 */
|
||||
private String jdRemark;
|
||||
/** 联查:本地京东单收件地址 jd_order.address(闲鱼详情常不返回明文地址) */
|
||||
private String jdAddress;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ public interface IErpGoofishOrderService {
|
||||
|
||||
int pullAllEnabled(int lookbackHours);
|
||||
|
||||
/** 按配置的起始天数 + 时间分段,尽量拉全历史订单(update_time) */
|
||||
int pullOrdersForAppKeyFullHistory(String appKey);
|
||||
|
||||
int pullAllEnabledFullHistory();
|
||||
|
||||
void refreshDetail(Long id);
|
||||
|
||||
void retryShip(Long id);
|
||||
|
||||
@@ -53,6 +53,7 @@ public class GoofishOrderPipeline {
|
||||
try {
|
||||
ErpGoofishOrder row = upsertFromNotify(appid, notifyBody, notifyBody.toJSONString());
|
||||
tryLinkJdOrder(row);
|
||||
mergeSummaryFromOrderDetailShape(row, notifyBody);
|
||||
refreshDetail(row);
|
||||
syncWaybillFromRedis(row);
|
||||
tryAutoShip(row);
|
||||
@@ -67,6 +68,7 @@ public class GoofishOrderPipeline {
|
||||
}
|
||||
ErpGoofishOrder row = upsertFromNotify(appKey, item, lastNotifyJson);
|
||||
tryLinkJdOrder(row);
|
||||
mergeSummaryFromOrderDetailShape(row, item);
|
||||
refreshDetail(row);
|
||||
syncWaybillFromRedis(row);
|
||||
tryAutoShip(row);
|
||||
@@ -151,7 +153,7 @@ public class GoofishOrderPipeline {
|
||||
if (jo != null && jo.getIntValue("code") == 0) {
|
||||
JSONObject data = jo.getJSONObject("data");
|
||||
if (data != null) {
|
||||
mergeSummaryFromDetail(row, data);
|
||||
mergeSummaryFromOrderDetailShape(row, data);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
@@ -159,34 +161,212 @@ public class GoofishOrderPipeline {
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeSummaryFromDetail(ErpGoofishOrder row, JSONObject data) {
|
||||
/**
|
||||
* 合并「订单详情 / 订单列表 / 推送」等同一 schema(order_detail)上的展示与发货摘要字段。
|
||||
* 列表与推送含 prov_name、city_name、area_name、town_name、address,详情接口常不含明文地址。
|
||||
*/
|
||||
private void mergeSummaryFromOrderDetailShape(ErpGoofishOrder row, JSONObject data) {
|
||||
if (row == null || row.getId() == null || data == null) {
|
||||
return;
|
||||
}
|
||||
ErpGoofishOrder patch = new ErpGoofishOrder();
|
||||
patch.setId(row.getId());
|
||||
boolean any = false;
|
||||
JSONObject goods = data.getJSONObject("goods");
|
||||
if (goods != null) {
|
||||
String title = goods.getString("title");
|
||||
if (StringUtils.isNotEmpty(title)) {
|
||||
patch.setGoodsTitle(title.trim());
|
||||
}
|
||||
String cover = firstGoodsCoverUrl(goods);
|
||||
if (StringUtils.isNotEmpty(cover)) {
|
||||
patch.setGoodsImageUrl(cover);
|
||||
}
|
||||
Long gPid = goods.getLong("product_id");
|
||||
if (gPid != null) {
|
||||
patch.setProductId(gPid);
|
||||
}
|
||||
Long gIid = goods.getLong("item_id");
|
||||
if (gIid != null) {
|
||||
patch.setItemId(gIid);
|
||||
}
|
||||
}
|
||||
String wb = data.getString("waybill_no");
|
||||
if (StringUtils.isNotEmpty(wb)) {
|
||||
patch.setDetailWaybillNo(wb.trim());
|
||||
}
|
||||
String dec = data.getString("express_code");
|
||||
if (StringUtils.isNotEmpty(dec)) {
|
||||
patch.setDetailExpressCode(dec.trim());
|
||||
}
|
||||
String den = data.getString("express_name");
|
||||
if (StringUtils.isNotEmpty(den)) {
|
||||
patch.setDetailExpressName(den.trim());
|
||||
}
|
||||
String bn = data.getString("buyer_nick");
|
||||
if (StringUtils.isNotEmpty(bn)) {
|
||||
patch.setBuyerNick(bn.trim());
|
||||
}
|
||||
Long payFen = data.getLong("pay_amount");
|
||||
if (payFen != null) {
|
||||
patch.setPayAmount(payFen);
|
||||
}
|
||||
String seller = data.getString("seller_name");
|
||||
if (StringUtils.isEmpty(row.getUserName()) && StringUtils.isNotEmpty(seller)) {
|
||||
patch.setUserName(seller.trim());
|
||||
}
|
||||
patch.setReceiverName(firstNonEmpty(data, "receiver_name", "ship_name", "consignee_name", "contact_name"));
|
||||
patch.setReceiverMobile(firstNonEmpty(data, "receiver_mobile", "ship_mobile", "receiver_phone", "contact_mobile"));
|
||||
patch.setReceiverAddress(firstNonEmpty(data, "receiver_address", "ship_address", "detail_address",
|
||||
"full_address", "address"));
|
||||
String prov = firstNonEmpty(data, "receiver_province", "ship_prov_name", "prov", "prov_name");
|
||||
String city = firstNonEmpty(data, "receiver_city", "ship_city_name", "city", "city_name");
|
||||
String area = firstNonEmpty(data, "receiver_district", "receiver_area", "ship_area_name", "district", "area_name");
|
||||
String town = firstNonEmpty(data, "town_name", "receiver_town", "ship_town_name", "street_name");
|
||||
String regionJoined = joinWithSpace(prov, city, area, town);
|
||||
if (StringUtils.isNotEmpty(regionJoined)) {
|
||||
patch.setReceiverRegion(regionJoined);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(prov)) {
|
||||
patch.setRecvProvName(prov.trim());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(city)) {
|
||||
patch.setRecvCityName(city.trim());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(area)) {
|
||||
patch.setRecvAreaName(area.trim());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(town)) {
|
||||
patch.setRecvTownName(town.trim());
|
||||
}
|
||||
JSONObject recv = data.getJSONObject("receiver");
|
||||
if (recv != null) {
|
||||
if (StringUtils.isEmpty(patch.getReceiverName())) {
|
||||
patch.setReceiverName(recv.getString("name"));
|
||||
}
|
||||
if (StringUtils.isEmpty(patch.getReceiverMobile())) {
|
||||
String m = recv.getString("mobile");
|
||||
if (StringUtils.isEmpty(m)) {
|
||||
m = recv.getString("phone");
|
||||
}
|
||||
patch.setReceiverMobile(m);
|
||||
}
|
||||
if (StringUtils.isEmpty(patch.getReceiverAddress())) {
|
||||
patch.setReceiverAddress(recv.getString("address"));
|
||||
}
|
||||
}
|
||||
Integer os = data.getInteger("order_status");
|
||||
if (os != null) {
|
||||
patch.setOrderStatus(os);
|
||||
row.setOrderStatus(os);
|
||||
any = true;
|
||||
}
|
||||
Integer rs = data.getInteger("refund_status");
|
||||
if (rs != null) {
|
||||
patch.setRefundStatus(rs);
|
||||
row.setRefundStatus(rs);
|
||||
any = true;
|
||||
}
|
||||
Long mt = data.getLong("modify_time");
|
||||
if (mt == null) {
|
||||
mt = data.getLong("order_modify_time");
|
||||
}
|
||||
if (mt == null) {
|
||||
mt = data.getLong("update_time");
|
||||
}
|
||||
if (mt != null) {
|
||||
patch.setModifyTime(mt);
|
||||
row.setModifyTime(mt);
|
||||
any = true;
|
||||
}
|
||||
if (any) {
|
||||
patch.setUpdateTime(DateUtils.getNowDate());
|
||||
erpGoofishOrderMapper.update(patch);
|
||||
fillReceiverFromJdOrder(patch, row);
|
||||
patch.setUpdateTime(DateUtils.getNowDate());
|
||||
erpGoofishOrderMapper.update(patch);
|
||||
applySummaryPatchToRow(row, patch);
|
||||
}
|
||||
|
||||
/** 闲鱼详情常不返回明文地址:用已关联的 jd_order.address 兜底;平台已回收货人/分级地址时不覆盖姓名 */
|
||||
private void fillReceiverFromJdOrder(ErpGoofishOrder patch, ErpGoofishOrder row) {
|
||||
if (row.getJdOrderId() == null) {
|
||||
return;
|
||||
}
|
||||
boolean platformCare = StringUtils.isNotEmpty(patch.getReceiverName())
|
||||
|| StringUtils.isNotEmpty(patch.getReceiverMobile())
|
||||
|| StringUtils.isNotEmpty(patch.getRecvProvName())
|
||||
|| StringUtils.isNotEmpty(patch.getRecvCityName())
|
||||
|| StringUtils.isNotEmpty(patch.getRecvAreaName())
|
||||
|| StringUtils.isNotEmpty(patch.getRecvTownName());
|
||||
JDOrder jd = jdOrderService.selectJDOrderById(row.getJdOrderId());
|
||||
if (jd == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isEmpty(patch.getReceiverAddress()) && StringUtils.isNotEmpty(jd.getAddress())) {
|
||||
patch.setReceiverAddress(jd.getAddress().trim());
|
||||
}
|
||||
if (platformCare) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isEmpty(patch.getReceiverName()) && StringUtils.isNotEmpty(jd.getBuyer())) {
|
||||
patch.setReceiverName(jd.getBuyer().trim());
|
||||
}
|
||||
}
|
||||
|
||||
private void applySummaryPatchToRow(ErpGoofishOrder row, ErpGoofishOrder patch) {
|
||||
if (patch.getGoodsTitle() != null) {
|
||||
row.setGoodsTitle(patch.getGoodsTitle());
|
||||
}
|
||||
if (patch.getGoodsImageUrl() != null) {
|
||||
row.setGoodsImageUrl(patch.getGoodsImageUrl());
|
||||
}
|
||||
if (patch.getBuyerNick() != null) {
|
||||
row.setBuyerNick(patch.getBuyerNick());
|
||||
}
|
||||
if (patch.getPayAmount() != null) {
|
||||
row.setPayAmount(patch.getPayAmount());
|
||||
}
|
||||
if (patch.getDetailWaybillNo() != null) {
|
||||
row.setDetailWaybillNo(patch.getDetailWaybillNo());
|
||||
}
|
||||
if (patch.getDetailExpressCode() != null) {
|
||||
row.setDetailExpressCode(patch.getDetailExpressCode());
|
||||
}
|
||||
if (patch.getDetailExpressName() != null) {
|
||||
row.setDetailExpressName(patch.getDetailExpressName());
|
||||
}
|
||||
if (patch.getReceiverName() != null) {
|
||||
row.setReceiverName(patch.getReceiverName());
|
||||
}
|
||||
if (patch.getReceiverMobile() != null) {
|
||||
row.setReceiverMobile(patch.getReceiverMobile());
|
||||
}
|
||||
if (patch.getReceiverAddress() != null) {
|
||||
row.setReceiverAddress(patch.getReceiverAddress());
|
||||
}
|
||||
if (patch.getReceiverRegion() != null) {
|
||||
row.setReceiverRegion(patch.getReceiverRegion());
|
||||
}
|
||||
if (patch.getRecvProvName() != null) {
|
||||
row.setRecvProvName(patch.getRecvProvName());
|
||||
}
|
||||
if (patch.getRecvCityName() != null) {
|
||||
row.setRecvCityName(patch.getRecvCityName());
|
||||
}
|
||||
if (patch.getRecvAreaName() != null) {
|
||||
row.setRecvAreaName(patch.getRecvAreaName());
|
||||
}
|
||||
if (patch.getRecvTownName() != null) {
|
||||
row.setRecvTownName(patch.getRecvTownName());
|
||||
}
|
||||
if (patch.getUserName() != null) {
|
||||
row.setUserName(patch.getUserName());
|
||||
}
|
||||
if (patch.getOrderStatus() != null) {
|
||||
row.setOrderStatus(patch.getOrderStatus());
|
||||
}
|
||||
if (patch.getRefundStatus() != null) {
|
||||
row.setRefundStatus(patch.getRefundStatus());
|
||||
}
|
||||
if (patch.getModifyTime() != null) {
|
||||
row.setModifyTime(patch.getModifyTime());
|
||||
}
|
||||
if (patch.getProductId() != null) {
|
||||
row.setProductId(patch.getProductId());
|
||||
}
|
||||
if (patch.getItemId() != null) {
|
||||
row.setItemId(patch.getItemId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +403,11 @@ public class GoofishOrderPipeline {
|
||||
if (row.getShipStatus() != null && row.getShipStatus() == 1) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isEmpty(row.getLocalWaybillNo())) {
|
||||
String waybill = row.getLocalWaybillNo();
|
||||
if (StringUtils.isEmpty(waybill)) {
|
||||
waybill = row.getDetailWaybillNo();
|
||||
}
|
||||
if (StringUtils.isEmpty(waybill)) {
|
||||
return;
|
||||
}
|
||||
ErpOpenConfig cfg = erpOpenConfigService.selectByAppKey(row.getAppKey());
|
||||
@@ -234,9 +418,27 @@ public class GoofishOrderPipeline {
|
||||
return;
|
||||
}
|
||||
ShipAddressParts addr = parseShipAddress(row.getDetailJson());
|
||||
if (addr == null || StringUtils.isEmpty(addr.shipName) || StringUtils.isEmpty(addr.shipMobile)
|
||||
if (addr == null) {
|
||||
addr = new ShipAddressParts();
|
||||
}
|
||||
enrichShipAddressFromJd(row, addr);
|
||||
if (StringUtils.isEmpty(addr.shipAddress)) {
|
||||
ShipAddressParts fromRow = receiverFieldsToShipParts(row);
|
||||
if (fromRow != null) {
|
||||
if (StringUtils.isEmpty(addr.shipName)) {
|
||||
addr.shipName = fromRow.shipName;
|
||||
}
|
||||
if (StringUtils.isEmpty(addr.shipMobile)) {
|
||||
addr.shipMobile = fromRow.shipMobile;
|
||||
}
|
||||
if (StringUtils.isEmpty(addr.shipAddress)) {
|
||||
addr.shipAddress = fromRow.shipAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(addr.shipName) || StringUtils.isEmpty(addr.shipMobile)
|
||||
|| StringUtils.isEmpty(addr.shipAddress)) {
|
||||
patchShipError(row, "详情中缺少收货人/手机/地址,请核对开放平台订单详情 JSON 字段");
|
||||
patchShipError(row, "缺少收货人/手机/地址:详情无字段时请关联京东单并维护地址,或等平台返回收货字段");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -258,7 +460,7 @@ public class GoofishOrderPipeline {
|
||||
if (StringUtils.isNotEmpty(addr.shipAreaName)) {
|
||||
ship.setShipAreaName(addr.shipAreaName);
|
||||
}
|
||||
ship.setWaybillNo(row.getLocalWaybillNo());
|
||||
ship.setWaybillNo(waybill.trim());
|
||||
ship.setExpressCode(expressCode);
|
||||
ship.setExpressName(expressName);
|
||||
String resp = ship.getResponseBody();
|
||||
@@ -308,6 +510,47 @@ public class GoofishOrderPipeline {
|
||||
String shipAreaName;
|
||||
}
|
||||
|
||||
private void enrichShipAddressFromJd(ErpGoofishOrder row, ShipAddressParts p) {
|
||||
if (row == null || p == null || row.getJdOrderId() == null) {
|
||||
return;
|
||||
}
|
||||
JDOrder jd = jdOrderService.selectJDOrderById(row.getJdOrderId());
|
||||
if (jd == null) {
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isEmpty(p.shipAddress) && StringUtils.isNotEmpty(jd.getAddress())) {
|
||||
p.shipAddress = jd.getAddress().trim();
|
||||
}
|
||||
if (StringUtils.isEmpty(p.shipName) && StringUtils.isNotEmpty(jd.getBuyer())) {
|
||||
p.shipName = jd.getBuyer().trim();
|
||||
}
|
||||
}
|
||||
|
||||
private ShipAddressParts receiverFieldsToShipParts(ErpGoofishOrder row) {
|
||||
if (row == null) {
|
||||
return null;
|
||||
}
|
||||
String regionLine = row.getReceiverRegion();
|
||||
if (StringUtils.isEmpty(regionLine)) {
|
||||
regionLine = joinWithSpace(row.getRecvProvName(), row.getRecvCityName(), row.getRecvAreaName(), row.getRecvTownName());
|
||||
}
|
||||
if (StringUtils.isEmpty(row.getReceiverAddress()) && StringUtils.isEmpty(regionLine)) {
|
||||
return null;
|
||||
}
|
||||
ShipAddressParts p = new ShipAddressParts();
|
||||
p.shipName = row.getReceiverName();
|
||||
p.shipMobile = row.getReceiverMobile();
|
||||
p.shipAddress = row.getReceiverAddress();
|
||||
if (StringUtils.isNotEmpty(regionLine)) {
|
||||
if (StringUtils.isNotEmpty(p.shipAddress)) {
|
||||
p.shipAddress = regionLine + " " + p.shipAddress;
|
||||
} else {
|
||||
p.shipAddress = regionLine;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
private ShipAddressParts parseShipAddress(String detailJson) {
|
||||
if (StringUtils.isEmpty(detailJson)) {
|
||||
return null;
|
||||
@@ -323,11 +566,15 @@ public class GoofishOrderPipeline {
|
||||
ShipAddressParts p = new ShipAddressParts();
|
||||
p.shipName = firstNonEmpty(data, "ship_name", "receiver_name", "consignee", "contact_name");
|
||||
p.shipMobile = firstNonEmpty(data, "ship_mobile", "receiver_mobile", "receiver_phone", "contact_mobile");
|
||||
p.shipAddress = firstNonEmpty(data, "ship_address", "receiver_address", "detail_address");
|
||||
p.shipAddress = firstNonEmpty(data, "ship_address", "receiver_address", "detail_address", "address");
|
||||
p.shipDistrictId = firstInt(data, "ship_district_id", "receiver_district_id");
|
||||
p.shipProvName = firstNonEmpty(data, "ship_prov_name", "receiver_province", "prov");
|
||||
p.shipCityName = firstNonEmpty(data, "ship_city_name", "receiver_city", "city");
|
||||
p.shipAreaName = firstNonEmpty(data, "ship_area_name", "receiver_area", "area", "district");
|
||||
p.shipProvName = firstNonEmpty(data, "ship_prov_name", "receiver_province", "prov", "prov_name");
|
||||
p.shipCityName = firstNonEmpty(data, "ship_city_name", "receiver_city", "city", "city_name");
|
||||
p.shipAreaName = firstNonEmpty(data, "ship_area_name", "receiver_area", "area", "district", "area_name");
|
||||
String shipTown = firstNonEmpty(data, "town_name", "ship_town_name", "receiver_town");
|
||||
if (StringUtils.isNotEmpty(shipTown) && StringUtils.isEmpty(p.shipAddress)) {
|
||||
p.shipAddress = shipTown;
|
||||
}
|
||||
JSONObject recv = data.getJSONObject("receiver");
|
||||
if (recv != null) {
|
||||
if (StringUtils.isEmpty(p.shipName)) {
|
||||
@@ -346,6 +593,43 @@ public class GoofishOrderPipeline {
|
||||
return p;
|
||||
}
|
||||
|
||||
/** 开放平台 goods.images 首元素,或其它常见单图字段 */
|
||||
private static String firstGoodsCoverUrl(JSONObject goods) {
|
||||
if (goods == null) {
|
||||
return null;
|
||||
}
|
||||
for (String k : new String[]{"image", "pic", "cover", "main_image", "img", "item_pic"}) {
|
||||
String v = goods.getString(k);
|
||||
if (StringUtils.isNotEmpty(v)) {
|
||||
return v.trim();
|
||||
}
|
||||
}
|
||||
JSONArray images = goods.getJSONArray("images");
|
||||
if (images == null || images.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Object first = images.get(0);
|
||||
if (first == null) {
|
||||
return null;
|
||||
}
|
||||
String u = first.toString().trim();
|
||||
return StringUtils.isNotEmpty(u) ? u : null;
|
||||
}
|
||||
|
||||
/** 省、市、区、街道等与列表接口 prov_name/city_name/area_name/town_name 对齐拼接 */
|
||||
private static String joinWithSpace(String... parts) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String p : parts) {
|
||||
if (StringUtils.isNotEmpty(p)) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(p.trim());
|
||||
}
|
||||
}
|
||||
return sb.length() == 0 ? null : sb.toString();
|
||||
}
|
||||
|
||||
private static String firstNonEmpty(JSONObject o, String... keys) {
|
||||
if (o == null) {
|
||||
return null;
|
||||
@@ -372,23 +656,76 @@ public class GoofishOrderPipeline {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增量拉单:按 update_time ∈ [now−lookbackHours, now]
|
||||
*/
|
||||
public int pullForAppKey(String appKey, int lookbackHours) {
|
||||
if (StringUtils.isEmpty(appKey)) {
|
||||
return 0;
|
||||
}
|
||||
IERPAccount cred = erpAccountResolver.resolve(appKey);
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
long start = now - (long) lookbackHours * 3600L;
|
||||
return pullForAppKeyUpdateTimeRange(appKey, start, now);
|
||||
}
|
||||
|
||||
/**
|
||||
* 长历史全量:从「当前时间 − pullFullHistoryDays」起,按 pullTimeChunkSeconds 切 update_time 窗口逐段拉取;
|
||||
* 每段内 page_size、page_no 与开放平台上限对齐,降低 page_no×page_size 超 1 万的风险。
|
||||
*/
|
||||
public int pullForAppKeyFullHistory(String appKey) {
|
||||
if (StringUtils.isEmpty(appKey)) {
|
||||
return 0;
|
||||
}
|
||||
long now = System.currentTimeMillis() / 1000;
|
||||
int days = goofishProperties.getPullFullHistoryDays();
|
||||
if (days < 1) {
|
||||
days = 1;
|
||||
}
|
||||
long start = now - (long) days * 86400L;
|
||||
int chunk = goofishProperties.getPullTimeChunkSeconds();
|
||||
if (chunk < 3600) {
|
||||
chunk = 86400;
|
||||
}
|
||||
int total = 0;
|
||||
for (long t = start; t <= now; t += chunk) {
|
||||
long end = Math.min(t + chunk - 1, now);
|
||||
if (end < t) {
|
||||
break;
|
||||
}
|
||||
total += pullForAppKeyUpdateTimeRange(appKey, t, end);
|
||||
try {
|
||||
Thread.sleep(150);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按开放平台「订单列表」接口,限定 update_time 时间戳区间(秒,闭区间)拉取并落库。
|
||||
*/
|
||||
public int pullForAppKeyUpdateTimeRange(String appKey, long updateTimeStartSec, long updateTimeEndSec) {
|
||||
if (StringUtils.isEmpty(appKey) || updateTimeEndSec < updateTimeStartSec) {
|
||||
return 0;
|
||||
}
|
||||
IERPAccount cred = erpAccountResolver.resolve(appKey);
|
||||
List<Long> authorizeIds = fetchAuthorizeIds(cred);
|
||||
int pageSize = Math.min(100, Math.max(1, goofishProperties.getPullPageSize()));
|
||||
int maxPages = Math.min(100, Math.max(1, goofishProperties.getPullMaxPagesPerShop()));
|
||||
if ((long) maxPages * pageSize > 10000L) {
|
||||
maxPages = 10000 / pageSize;
|
||||
log.warn("闲管家拉单: pull-max-pages 与 pull-page-size 乘积超过 10000,已收敛 maxPages={}", maxPages);
|
||||
}
|
||||
int saved = 0;
|
||||
int maxPages = goofishProperties.getPullMaxPagesPerShop();
|
||||
for (Long aid : authorizeIds) {
|
||||
int page = 1;
|
||||
while (page <= maxPages) {
|
||||
OrderListQueryRequest q = new OrderListQueryRequest(cred);
|
||||
q.setAuthorizeId(aid);
|
||||
q.setUpdateTime(start, now);
|
||||
q.setPage(page, 20);
|
||||
q.setUpdateTime(updateTimeStartSec, updateTimeEndSec);
|
||||
q.setPage(page, pageSize);
|
||||
String resp;
|
||||
try {
|
||||
resp = q.getResponseBody();
|
||||
@@ -411,7 +748,12 @@ public class GoofishOrderPipeline {
|
||||
applyListOrNotifyItem(appKey, item, item.toJSONString());
|
||||
saved++;
|
||||
}
|
||||
if (list.size() < 20) {
|
||||
if (list.size() < pageSize) {
|
||||
break;
|
||||
}
|
||||
if (page == maxPages) {
|
||||
log.warn("闲管家拉单已达最大页数 appKey={} aid={} 区间[{},{}];若订单更多请缩小 pull-time-chunk-seconds",
|
||||
appKey, aid, updateTimeStartSec, updateTimeEndSec);
|
||||
break;
|
||||
}
|
||||
page++;
|
||||
|
||||
@@ -90,6 +90,27 @@ public class ErpGoofishOrderServiceImpl implements IErpGoofishOrderService {
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pullOrdersForAppKeyFullHistory(String appKey) {
|
||||
return goofishOrderPipeline.pullForAppKeyFullHistory(appKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int pullAllEnabledFullHistory() {
|
||||
int total = 0;
|
||||
List<ErpOpenConfig> cfgs = erpOpenConfigService.selectEnabledOrderBySort();
|
||||
if (cfgs == null) {
|
||||
return 0;
|
||||
}
|
||||
for (ErpOpenConfig c : cfgs) {
|
||||
if (c.getAppKey() == null) {
|
||||
continue;
|
||||
}
|
||||
total += goofishOrderPipeline.pullForAppKeyFullHistory(c.getAppKey());
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshDetail(Long id) {
|
||||
ErpGoofishOrder row = erpGoofishOrderMapper.selectById(id);
|
||||
|
||||
@@ -14,6 +14,21 @@
|
||||
<result property="modifyTime" column="modify_time"/>
|
||||
<result property="productId" column="product_id"/>
|
||||
<result property="itemId" column="item_id"/>
|
||||
<result property="goodsTitle" column="goods_title"/>
|
||||
<result property="goodsImageUrl" column="goods_image_url"/>
|
||||
<result property="buyerNick" column="buyer_nick"/>
|
||||
<result property="payAmount" column="pay_amount"/>
|
||||
<result property="detailWaybillNo" column="detail_waybill_no"/>
|
||||
<result property="detailExpressCode" column="detail_express_code"/>
|
||||
<result property="detailExpressName" column="detail_express_name"/>
|
||||
<result property="receiverName" column="receiver_name"/>
|
||||
<result property="receiverMobile" column="receiver_mobile"/>
|
||||
<result property="receiverAddress" column="receiver_address"/>
|
||||
<result property="receiverRegion" column="receiver_region"/>
|
||||
<result property="recvProvName" column="recv_prov_name"/>
|
||||
<result property="recvCityName" column="recv_city_name"/>
|
||||
<result property="recvAreaName" column="recv_area_name"/>
|
||||
<result property="recvTownName" column="recv_town_name"/>
|
||||
<result property="detailJson" column="detail_json"/>
|
||||
<result property="lastNotifyJson" column="last_notify_json"/>
|
||||
<result property="jdOrderId" column="jd_order_id"/>
|
||||
@@ -26,13 +41,17 @@
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="jdThirdPartyOrderNo" column="jd_third_party_order_no"/>
|
||||
<result property="jdRemark" column="jd_remark"/>
|
||||
<result property="jdAddress" column="jd_address"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectJoinVo">
|
||||
select e.id, e.app_key, e.seller_id, e.user_name, e.order_no, e.order_type, e.order_status, e.refund_status,
|
||||
e.modify_time, e.product_id, e.item_id, e.detail_json, e.last_notify_json, e.jd_order_id, e.local_waybill_no,
|
||||
e.modify_time, e.product_id, e.item_id, e.goods_title, e.goods_image_url, e.buyer_nick, e.pay_amount, e.detail_waybill_no,
|
||||
e.detail_express_code, e.detail_express_name, e.receiver_name, e.receiver_mobile, e.receiver_address,
|
||||
e.receiver_region, e.recv_prov_name, e.recv_city_name, e.recv_area_name, e.recv_town_name,
|
||||
e.detail_json, e.last_notify_json, e.jd_order_id, e.local_waybill_no,
|
||||
e.ship_status, e.ship_error, e.ship_time, e.ship_express_code, e.create_time, e.update_time,
|
||||
o.third_party_order_no as jd_third_party_order_no, o.remark as jd_remark
|
||||
o.third_party_order_no as jd_third_party_order_no, o.remark as jd_remark, o.address as jd_address
|
||||
from erp_goofish_order e
|
||||
left join jd_order o on e.jd_order_id = o.id
|
||||
</sql>
|
||||
@@ -68,10 +87,16 @@
|
||||
<insert id="insert" parameterType="com.ruoyi.jarvis.domain.ErpGoofishOrder" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into erp_goofish_order
|
||||
(app_key, seller_id, user_name, order_no, order_type, order_status, refund_status, modify_time, product_id, item_id,
|
||||
goods_title, goods_image_url, buyer_nick, pay_amount, detail_waybill_no, detail_express_code, detail_express_name,
|
||||
receiver_name, receiver_mobile, receiver_address, receiver_region,
|
||||
recv_prov_name, recv_city_name, recv_area_name, recv_town_name,
|
||||
detail_json, last_notify_json, jd_order_id, local_waybill_no, ship_status, ship_error, ship_time, ship_express_code,
|
||||
create_time, update_time)
|
||||
values
|
||||
(#{appKey}, #{sellerId}, #{userName}, #{orderNo}, #{orderType}, #{orderStatus}, #{refundStatus}, #{modifyTime}, #{productId}, #{itemId},
|
||||
#{goodsTitle}, #{goodsImageUrl}, #{buyerNick}, #{payAmount}, #{detailWaybillNo}, #{detailExpressCode}, #{detailExpressName},
|
||||
#{receiverName}, #{receiverMobile}, #{receiverAddress}, #{receiverRegion},
|
||||
#{recvProvName}, #{recvCityName}, #{recvAreaName}, #{recvTownName},
|
||||
#{detailJson}, #{lastNotifyJson}, #{jdOrderId}, #{localWaybillNo}, #{shipStatus}, #{shipError}, #{shipTime}, #{shipExpressCode},
|
||||
#{createTime}, #{updateTime})
|
||||
</insert>
|
||||
@@ -87,6 +112,21 @@
|
||||
<if test="modifyTime != null">modify_time = #{modifyTime},</if>
|
||||
<if test="productId != null">product_id = #{productId},</if>
|
||||
<if test="itemId != null">item_id = #{itemId},</if>
|
||||
<if test="goodsTitle != null">goods_title = #{goodsTitle},</if>
|
||||
<if test="goodsImageUrl != null">goods_image_url = #{goodsImageUrl},</if>
|
||||
<if test="buyerNick != null">buyer_nick = #{buyerNick},</if>
|
||||
<if test="payAmount != null">pay_amount = #{payAmount},</if>
|
||||
<if test="detailWaybillNo != null">detail_waybill_no = #{detailWaybillNo},</if>
|
||||
<if test="detailExpressCode != null">detail_express_code = #{detailExpressCode},</if>
|
||||
<if test="detailExpressName != null">detail_express_name = #{detailExpressName},</if>
|
||||
<if test="receiverName != null">receiver_name = #{receiverName},</if>
|
||||
<if test="receiverMobile != null">receiver_mobile = #{receiverMobile},</if>
|
||||
<if test="receiverAddress != null">receiver_address = #{receiverAddress},</if>
|
||||
<if test="receiverRegion != null">receiver_region = #{receiverRegion},</if>
|
||||
<if test="recvProvName != null">recv_prov_name = #{recvProvName},</if>
|
||||
<if test="recvCityName != null">recv_city_name = #{recvCityName},</if>
|
||||
<if test="recvAreaName != null">recv_area_name = #{recvAreaName},</if>
|
||||
<if test="recvTownName != null">recv_town_name = #{recvTownName},</if>
|
||||
<if test="detailJson != null">detail_json = #{detailJson},</if>
|
||||
<if test="lastNotifyJson != null">last_notify_json = #{lastNotifyJson},</if>
|
||||
<if test="jdOrderId != null">jd_order_id = #{jdOrderId},</if>
|
||||
|
||||
Reference in New Issue
Block a user