This commit is contained in:
zjf committed 2026-10-29 19:51:45 +08:00
1 parent d11165bd3c
commit b2954d3957
2 files changed
+84 -33

No files matched your search

@@ -26,15 +26,24 @@ public class SmHotelDownstreamPushLogServiceImpl
@Override
public Page<SmHotelDownstreamPushLogEntity> pageLogs(Page<SmHotelDownstreamPushLogEntity> page,
SmHotelDownstreamPushLogEntity query) {
// 列表不查 request_body/response_body(mediumtext):全量推后行数暴涨,带大字段会极慢;详情再查全文
String partner = query == null ? null : query.getPartnerCode();
Long syncLogId = query == null ? null : query.getSyncLogId();
Long hotelId = query == null ? null : query.getHotelId();
String extHotelId = query == null ? null : query.getExtHotelId();
String action = query == null ? null : query.getAction();
String success = query == null ? null : query.getSuccess();
return baseMapper.selectPage(page, Wrappers.<SmHotelDownstreamPushLogEntity>lambdaQuery()
.eq(StrUtil.isNotBlank(query.getPartnerCode()), SmHotelDownstreamPushLogEntity::getPartnerCode,
query.getPartnerCode())
.eq(query.getSyncLogId() != null, SmHotelDownstreamPushLogEntity::getSyncLogId, query.getSyncLogId())
.eq(query.getHotelId() != null, SmHotelDownstreamPushLogEntity::getHotelId, query.getHotelId())
.eq(StrUtil.isNotBlank(query.getExtHotelId()), SmHotelDownstreamPushLogEntity::getExtHotelId,
query.getExtHotelId())
.eq(StrUtil.isNotBlank(query.getAction()), SmHotelDownstreamPushLogEntity::getAction, query.getAction())
.eq(StrUtil.isNotBlank(query.getSuccess()), SmHotelDownstreamPushLogEntity::getSuccess, query.getSuccess())
.select(SmHotelDownstreamPushLogEntity.class, info -> {
String col = info.getColumn();
return !"request_body".equalsIgnoreCase(col) && !"response_body".equalsIgnoreCase(col);
})
.eq(StrUtil.isNotBlank(partner), SmHotelDownstreamPushLogEntity::getPartnerCode, partner)
.eq(syncLogId != null, SmHotelDownstreamPushLogEntity::getSyncLogId, syncLogId)
.eq(hotelId != null, SmHotelDownstreamPushLogEntity::getHotelId, hotelId)
.eq(StrUtil.isNotBlank(extHotelId), SmHotelDownstreamPushLogEntity::getExtHotelId, extHotelId)
.eq(StrUtil.isNotBlank(action), SmHotelDownstreamPushLogEntity::getAction, action)
.eq(StrUtil.isNotBlank(success), SmHotelDownstreamPushLogEntity::getSuccess, success)
.orderByDesc(SmHotelDownstreamPushLogEntity::getCreateTime));
}
@@ -451,6 +451,19 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
Map<String, Object> one;
if (SmHotelDownstreamPushKind.isClose(kind)) {
one = closeHotelDailyToPartner(hotel, partner, null);
// 圣诺 getInfo 确认对方无店时关房会跳过,按 skip 统计,不算失败
if (Boolean.TRUE.equals(one.get("skipped"))) {
one.put("partnerCode", partner);
one.put("pushKind", SmHotelDownstreamPushKind.SKIP);
Map<String, Object> result = new HashMap<>(8);
result.put("pushKind", SmHotelDownstreamPushKind.SKIP);
result.put("skipped", true);
result.put("skipReason", one.get("skipReason"));
result.put("partners", List.of(partner));
result.put("partnerResults", List.of(one));
result.put("partnerErrors", Collections.emptyList());
return R.ok(result);
}
one.put("pushKind", SmHotelDownstreamPushKind.CLOSE);
one.put("closed", true);
}
@@ -552,7 +565,7 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
/**
* 可售推 / 关房推 / 纯跳过(总览 §5.1)。
* SKIP:无酒店或无产品;CLOSE:有产品但下架或窗口无日历;SELL:上架+有产品+窗口有日历。
* 圣诺:未填外部酒店ID(sHotelId/eid) 不调对方接口;关房仅在已有 ns 映射时可继续。
* 圣诺:未填外部酒店ID(sHotelId/eid) 不调对方接口(可售/关房均跳过)。
*/
private String resolveDownstreamPushKind(SmHotelEntity hotel, String partnerCode) {
if (hotel == null) {
@@ -564,6 +577,10 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
if (productCount == null || productCount <= 0) {
return SmHotelDownstreamPushKind.SKIP;
}
// 圣诺无 eid:对方无法认店,关房也会「更新失败」,直接跳过
if (isShengnuoPartner(partnerCode) && StrUtil.isBlank(StrUtil.trim(hotel.getSHotelId()))) {
return SmHotelDownstreamPushKind.SKIP;
}
boolean offline = "OFFLINE".equalsIgnoreCase(hotel.getUpstreamStatus());
LocalDate[] window = resolveDownstreamDailyWindow(partnerCode);
Long dailyCount = dailyMapper.selectCount(Wrappers.<SmHotelDailyEntity>lambdaQuery()
@@ -571,15 +588,7 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
.ge(SmHotelDailyEntity::getStayDate, window[0])
.le(SmHotelDailyEntity::getStayDate, window[1]));
boolean hasDaily = dailyCount != null && dailyCount > 0;
boolean needClose = offline || !hasDaily;
if (isShengnuoPartner(partnerCode) && StrUtil.isBlank(StrUtil.trim(hotel.getSHotelId()))) {
// 可售推必须 getInfo(eid),无 eid 直接跳过;关房仅 Redis 已有 nsHotelId 时可不调 getInfo
if (needClose && hasShengnuoNsMapping(partnerCode, hotelId)) {
return SmHotelDownstreamPushKind.CLOSE;
}
return SmHotelDownstreamPushKind.SKIP;
}
if (needClose) {
if (offline || !hasDaily) {
return SmHotelDownstreamPushKind.CLOSE;
}
return SmHotelDownstreamPushKind.SELL;
@@ -605,15 +614,6 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
return ds != null && SmHotelDownstreamProtocol.isShengnuo(ds.getProtocol());
}
/** 圣诺本地↔nsHotelId 缓存是否已存在(关房可不依赖 eid) */
private boolean hasShengnuoNsMapping(String partnerCode, Long hotelId) {
if (StrUtil.isBlank(partnerCode) || hotelId == null) {
return false;
}
cn.hutool.json.JSONObject cached = shengnuoIdMappingCache.getByLocal(partnerCode, hotelId);
return cached != null && cached.getLong("nsHotelId", 0L) > 0;
}
/**
* 关房推:环启推 dailyStatus=0;慧订推空价态窗口(对方打满房)。
* @param onlyProducts 非空时只关这些产品(环启);慧订忽略,整窗清空
@@ -834,22 +834,66 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
summary);
}
/** 圣诺关房:pushHotelClose(整店) */
/**
* 圣诺关房:先 getInfo(eid) 确认对方有店,再 pushHotelClose。
* 对方无档/getInfo 失败 → 跳过关房,避免无意义「更新失败」。
*/
private Map<String, Object> closeHotelDailyToShengnuo(SmHotelEntity hotel, String partnerCode) {
downstreamClient.assertPartnerReady(partnerCode);
HotelDownstreamProperties ds = channelConfigService.resolveDownstreamRuntime(partnerCode);
long nsHotelId = resolveShengnuoHotelId(partnerCode, ds, hotel);
String eid = StrUtil.trim(hotel.getSHotelId());
if (StrUtil.isBlank(eid)) {
String reason = "未填外部酒店ID(sHotelId/eid),跳过圣诺关房";
recordDownstreamPushSkip(partnerCode, hotel, reason);
Map<String, Object> skip = new HashMap<>(6);
skip.put("protocol", SmHotelDownstreamProtocol.SHENGNUO);
skip.put("skipped", true);
skip.put("skipReason", reason);
skip.put("dailyCloseCount", 0);
return skip;
}
long nsHotelId;
try {
cn.hutool.json.JSONObject infoResp = shengnuoAdapter.getInfo(partnerCode, ds, eid);
cn.hutool.json.JSONObject infoData = infoResp == null ? null : infoResp.getJSONObject("data");
nsHotelId = infoData == null ? 0L : infoData.getLong("id", 0L);
}
catch (Exception ex) {
String reason = "圣诺侧无此酒店或 getInfo 失败,跳过关房(eid=" + eid + "):" + ex.getMessage();
recordDownstreamPushSkip(partnerCode, hotel, reason);
log.info("|下游关房推送[圣诺]|跳过|hotelId={}|partner={}|eid={}|err={}|", hotel.getId(), partnerCode, eid,
ex.getMessage());
Map<String, Object> skip = new HashMap<>(6);
skip.put("protocol", SmHotelDownstreamProtocol.SHENGNUO);
skip.put("skipped", true);
skip.put("skipReason", reason);
skip.put("dailyCloseCount", 0);
return skip;
}
if (nsHotelId <= 0) {
String reason = "圣诺 getInfo 未返回酒店 id,跳过关房 eid=" + eid;
recordDownstreamPushSkip(partnerCode, hotel, reason);
Map<String, Object> skip = new HashMap<>(6);
skip.put("protocol", SmHotelDownstreamProtocol.SHENGNUO);
skip.put("skipped", true);
skip.put("skipReason", reason);
skip.put("dailyCloseCount", 0);
return skip;
}
Map<String, Object> body = new LinkedHashMap<>(shengnuoAdapter.signedBase(ds));
body.put("id", nsHotelId);
shengnuoAdapter.pushHotelClose(partnerCode, ds, hotel.getId(), String.valueOf(nsHotelId), body);
log.info("|下游关房推送[圣诺]|hotelId={}|partner={}|nsHotelId={}|", hotel.getId(), partnerCode, nsHotelId);
log.info("|下游关房推送[圣诺]|hotelId={}|partner={}|nsHotelId={}|eid={}|", hotel.getId(), partnerCode, nsHotelId,
eid);
Map<String, Object> result = new HashMap<>(6);
result.put("protocol", SmHotelDownstreamProtocol.SHENGNUO);
result.put("nsHotelId", nsHotelId);
result.put("eid", eid);
result.put("dailyCloseCount", 1);
return result;
}
/** 可售推等仍可用缓存 nsHotelId;关房已改为强制 getInfo 验活 */
private long resolveShengnuoHotelId(String partnerCode, HotelDownstreamProperties ds, SmHotelEntity hotel) {
cn.hutool.json.JSONObject cached = shengnuoIdMappingCache.getByLocal(partnerCode, hotel.getId());
if (cached != null) {
@@ -858,11 +902,9 @@ public class SmHotelMidServiceImpl implements SmHotelMidService {
return id;
}
}
// 无缓存时只能靠真实 eid 调 getInfo;禁止 hotelCode 回落
String eid = StrUtil.trim(hotel.getSHotelId());
if (StrUtil.isBlank(eid)) {
throw new IllegalArgumentException("圣诺关房缺少外部酒店ID(sHotelId)且无本地映射,跳过调接口 hotelId="
+ hotel.getId());
throw new IllegalArgumentException("圣诺缺少外部酒店ID(sHotelId)且无本地映射 hotelId=" + hotel.getId());
}
cn.hutool.json.JSONObject infoResp = shengnuoAdapter.getInfo(partnerCode, ds, eid);
cn.hutool.json.JSONObject infoData = infoResp == null ? null : infoResp.getJSONObject("data");