|
@@ -64,6 +64,7 @@ import java.nio.charset.StandardCharsets;
|
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
import java.util.function.Consumer;
|
|
import java.util.function.Consumer;
|
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Matcher;
|
|
|
import java.util.regex.Pattern;
|
|
import java.util.regex.Pattern;
|
|
@@ -213,7 +214,8 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
|
|
|
|
|
|
|
|
String cookie = extractCookie(mmap);
|
|
String cookie = extractCookie(mmap);
|
|
|
CarInfoVo car = quoteVo.getCarInfoVo();
|
|
CarInfoVo car = quoteVo.getCarInfoVo();
|
|
|
-
|
|
|
|
|
|
|
+ QuoteResultsVo quoteResultsVo = new QuoteResultsVo();
|
|
|
|
|
+ quoteResultsVo.setQuoteStatusEnum(InsOrderStatusEnum.QUOTE_FAIL);
|
|
|
// 带重试的获取报价编号、车型型号
|
|
// 带重试的获取报价编号、车型型号
|
|
|
Map<String, Object> xbResult = retry(() -> {
|
|
Map<String, Object> xbResult = retry(() -> {
|
|
|
try { return xbQuery(dto.getUsername(), cookie, car); }
|
|
try { return xbQuery(dto.getUsername(), cookie, car); }
|
|
@@ -222,14 +224,26 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
|
|
|
|
|
|
|
|
String quotationNo = str(xbResult, "quotationNo");
|
|
String quotationNo = str(xbResult, "quotationNo");
|
|
|
String modelcodexh = StringUtils.isBlank(str(xbResult, "modelcodexh")) ? car.getCarModelNo() : str(xbResult, "modelcodexh");
|
|
String modelcodexh = StringUtils.isBlank(str(xbResult, "modelcodexh")) ? car.getCarModelNo() : str(xbResult, "modelcodexh");
|
|
|
- log.info("modelcodexh: {}", str(xbResult, "modelcodexh"));
|
|
|
|
|
- log.info("modelcodexh: {}", modelcodexh);
|
|
|
|
|
|
|
+ log.info("XBResult_modelCodeXH: {}", str(xbResult, "modelcodexh"));
|
|
|
|
|
+ log.info("car.getCarModelNo()_modelCode_XH: {}", car.getCarModelNo());
|
|
|
|
|
|
|
|
// 报价前预处理-保存车辆信息、过滤车型等处理
|
|
// 报价前预处理-保存车辆信息、过滤车型等处理
|
|
|
- PreResult pre = prepareQuote(attr, mmap, car, modelcodexh, cookie, quotationNo, xbResult);
|
|
|
|
|
|
|
+ PreResult pre = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ pre = prepareQuote(attr, mmap, car, modelcodexh, cookie, quotationNo, xbResult);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("报价失败:保存车辆信息、过滤车型异常,{}",e.getMessage());
|
|
|
|
|
+ return quoteResultsVo;
|
|
|
|
|
+ }
|
|
|
// 报价
|
|
// 报价
|
|
|
- CoreResult core = executeQuote(quoteVo, quotationNo, dto, cookie, pre, gsInfo, attr);
|
|
|
|
|
- if (!core.success()) throw new SystemException("报价失败");
|
|
|
|
|
|
|
+ CoreResult core = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ core = executeQuote(quoteVo, quotationNo, dto, cookie, pre, gsInfo, attr);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("报价失败,{}",e.getMessage());
|
|
|
|
|
+ return quoteResultsVo;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!core.success()) return quoteResultsVo;
|
|
|
// 保存订单到MongoDB
|
|
// 保存订单到MongoDB
|
|
|
saveOrder(quoteVo, core);
|
|
saveOrder(quoteVo, core);
|
|
|
// 组装费用、评分、险种信息、续保标志
|
|
// 组装费用、评分、险种信息、续保标志
|
|
@@ -436,84 +450,101 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
|
|
|
|
|
|
|
|
private StepResult executeQuoteSteps(QuoteVo q, String quotationNo, LoginDTO dto,
|
|
private StepResult executeQuoteSteps(QuoteVo q, String quotationNo, LoginDTO dto,
|
|
|
String cookie, PreResult pre, Map<String, Object> gsInfo) {
|
|
String cookie, PreResult pre, Map<String, Object> gsInfo) {
|
|
|
- // 初始化重试次数和最大重试阈值
|
|
|
|
|
- int modelCodeRetryCount = 0;
|
|
|
|
|
- final int MAX_MODEL_CODE_RETRY = 2; // 限制最大重试次数,避免死循环
|
|
|
|
|
- String currentModelCodexh = pre.carDTO().getModelcodexh();
|
|
|
|
|
|
|
+ // 线程安全计数器,限制最多2次循环(初始0,最多执行2次)
|
|
|
|
|
+ AtomicInteger retryCount = new AtomicInteger(0);
|
|
|
PreResult currentPre = pre;
|
|
PreResult currentPre = pre;
|
|
|
- while (modelCodeRetryCount < MAX_MODEL_CODE_RETRY) {
|
|
|
|
|
- String decryptData = "";
|
|
|
|
|
|
|
+ StepResult stepResult = null;
|
|
|
|
|
+ final int MAX_RETRY_TIMES = 2;
|
|
|
|
|
+
|
|
|
|
|
+ while (retryCount.get() < MAX_RETRY_TIMES) {
|
|
|
try {
|
|
try {
|
|
|
- HttpHeaders h = buildQuoteStep1Headers(cookie);
|
|
|
|
|
- HtCrawlerSaveOneStepRequest r = new HtCrawlerSaveOneStepRequest(q, currentPre.carDTO(),
|
|
|
|
|
- currentPre.params(), quotationNo, currentPre.dataDTO(), dto, gsInfo);
|
|
|
|
|
- log.info("saveOneStept: {}", JSONObject.toJSONString(r));
|
|
|
|
|
- String body = req.saveOneStept(r, h).getBody().toString();
|
|
|
|
|
- String mealid = extractMealId(body);
|
|
|
|
|
- //机动车损失保险
|
|
|
|
|
- String limitAmount = extractLimitAmount(body);
|
|
|
|
|
- log.info("mealid: {}", mealid);
|
|
|
|
|
- log.info("limitAmount: {}", limitAmount);
|
|
|
|
|
- //组装驾意险参数,没有就空字符串
|
|
|
|
|
- String personalInsuredJSON = buildPersonalInsuredJSON(q);
|
|
|
|
|
-
|
|
|
|
|
- h = buildQuoteStep2Headers(cookie);
|
|
|
|
|
- //组装报价参数
|
|
|
|
|
- HtCrawlerQuoteRequest qr = new HtCrawlerQuoteRequest(q, mealid, limitAmount, "", personalInsuredJSON);
|
|
|
|
|
- //报价第一次
|
|
|
|
|
- decryptData = req.quote(qr, h);
|
|
|
|
|
- //处理重复投保返回终保日期的
|
|
|
|
|
- DuplQuoteResult duplQuoteResult = handleQuoteErrors(decryptData, q);
|
|
|
|
|
- if (duplQuoteResult.dupl()) {
|
|
|
|
|
- qr = new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON);
|
|
|
|
|
- decryptData = req.quote(qr, h);
|
|
|
|
|
|
|
+ stepResult = executeQuoteStepInternal(q, quotationNo, dto, cookie, currentPre, gsInfo);
|
|
|
|
|
+ // 正常获取到数据则跳出循环
|
|
|
|
|
+ if (stepResult != null && stepResult.data() != null && stepResult.data().getApplicationdto() != null) {
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 处理可能的录入的校验码有误
|
|
|
|
|
- HtCrawlerQuoteResponse.DataDTO data = null;
|
|
|
|
|
- try {
|
|
|
|
|
- data = resolveQuoteResponse(duplQuoteResult, decryptData, mealid,
|
|
|
|
|
- limitAmount, h, personalInsuredJSON);
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- decryptData = e.getMessage();
|
|
|
|
|
- // 检测modelcodexh不在平台车型范围内的异常
|
|
|
|
|
- if (decryptData.contains("errrorFlag") && decryptData.contains("carChange")) {
|
|
|
|
|
- modelCodeRetryCount++;
|
|
|
|
|
- log.warn("检测到modelcodexh[{}]不在平台车型范围内,开始第{}次重试获取新编码",
|
|
|
|
|
- currentModelCodexh, modelCodeRetryCount);
|
|
|
|
|
-
|
|
|
|
|
- // 提取新的modelcodexh
|
|
|
|
|
- Map<String, Object> map = MAPPER.readValue(decryptData, Map.class);
|
|
|
|
|
- List<Map<String, String>> list = (List)map.get("carModelList");
|
|
|
|
|
- String newModelCodexh = list.get(0).get("vehiclecode");
|
|
|
|
|
-
|
|
|
|
|
- currentModelCodexh = newModelCodexh;
|
|
|
|
|
-
|
|
|
|
|
- // 重新执行报价预处理流程
|
|
|
|
|
- AttributionInformationVo attr = q.getOrder().getAttributionInformationVo();
|
|
|
|
|
- log.info(map.get("unMatchVehicleFrameMessage")+"已重新执行prepareQuote,新modelcodexh:{}", currentModelCodexh);
|
|
|
|
|
- currentPre = prepareQuote(attr, gsInfo, q.getCarInfoVo(),
|
|
|
|
|
- currentModelCodexh, cookie, quotationNo, map);
|
|
|
|
|
- executeQuoteSteps(q, quotationNo, dto, cookie, currentPre, gsInfo);
|
|
|
|
|
-
|
|
|
|
|
- // 跳过当前循环,重新执行报价流程
|
|
|
|
|
- continue;
|
|
|
|
|
- } else {
|
|
|
|
|
- throw new SystemException(decryptData);
|
|
|
|
|
|
|
+ } catch (SystemException e) {
|
|
|
|
|
+ log.error("第{}次报价步骤执行异常: {}", retryCount.get() + 1, e.getMessage());
|
|
|
|
|
+ // 检测是否是车型不匹配需要重新查询的异常
|
|
|
|
|
+ if (e.getMessage().contains("errrorFlag") && e.getMessage().contains("carChange")) {
|
|
|
|
|
+ // 累加计数,超过次数则抛出异常
|
|
|
|
|
+ if (retryCount.incrementAndGet() >= MAX_RETRY_TIMES) {
|
|
|
|
|
+ if(e.getMessage().contains("上传的行业车型编码不在平台车型范围内,请核实。")) {
|
|
|
|
|
+ throw new SystemException("报价重试次数已达上限(" + MAX_RETRY_TIMES + "次),车型匹配失败。上传的行业车型编码不在平台车型范围内,请核实。", e.getMessage());
|
|
|
|
|
+ }else {
|
|
|
|
|
+ throw new SystemException("报价重试次数已达上限(" + MAX_RETRY_TIMES + "次),车型匹配失败。" + e.getMessage());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ // 提取新的modelcodexh并重新执行预处理
|
|
|
|
|
+ currentPre = rebuildPreResult(q, cookie, quotationNo, e.getMessage(), gsInfo);
|
|
|
|
|
+ continue; // 继续下一次循环
|
|
|
}
|
|
}
|
|
|
- return new StepResult(data, personalInsuredJSON);
|
|
|
|
|
-
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- modelCodeRetryCount++;
|
|
|
|
|
- if (modelCodeRetryCount >= MAX_MODEL_CODE_RETRY) {
|
|
|
|
|
- throw new SystemException(decryptData);
|
|
|
|
|
- }
|
|
|
|
|
- // 重试前短暂休眠,避免高频请求
|
|
|
|
|
- sleep(SHORT_DELAY_MS);
|
|
|
|
|
|
|
+ // 非车型匹配异常,直接抛出
|
|
|
|
|
+ throw e;
|
|
|
}
|
|
}
|
|
|
|
|
+ // 无有效数据且未触发异常时,累加计数
|
|
|
|
|
+ retryCount.incrementAndGet();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 最终仍无结果则返回空StepResult(或抛出异常,根据业务要求调整)
|
|
|
|
|
+ return stepResult != null ? stepResult : new StepResult(null, "");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 重构:抽离单次报价步骤执行的核心逻辑
|
|
|
|
|
+ */
|
|
|
|
|
+ private StepResult executeQuoteStepInternal(QuoteVo q, String quotationNo, LoginDTO dto,
|
|
|
|
|
+ String cookie, PreResult pre, Map<String, Object> gsInfo) {
|
|
|
|
|
+ String decryptData = "";
|
|
|
|
|
+ HttpHeaders h = buildQuoteStep1Headers(cookie);
|
|
|
|
|
+ HtCrawlerSaveOneStepRequest r = new HtCrawlerSaveOneStepRequest(q, pre.carDTO(),
|
|
|
|
|
+ pre.params(), quotationNo, pre.dataDTO(), dto, gsInfo);
|
|
|
|
|
+ log.info("saveOneStept: {}", JSONObject.toJSONString(r));
|
|
|
|
|
+ String body = req.saveOneStept(r, h).getBody().toString();
|
|
|
|
|
+ String mealid = extractMealId(body);
|
|
|
|
|
+ String limitAmount = extractLimitAmount(body);
|
|
|
|
|
+ log.info("mealid: {}", mealid);
|
|
|
|
|
+ log.info("limitAmount: {}", limitAmount);
|
|
|
|
|
+ //组装驾意险参数,没有就空字符串
|
|
|
|
|
+ String personalInsuredJSON = buildPersonalInsuredJSON(q);
|
|
|
|
|
+
|
|
|
|
|
+ h = buildQuoteStep2Headers(cookie);
|
|
|
|
|
+ //组装报价参数
|
|
|
|
|
+ HtCrawlerQuoteRequest qr = new HtCrawlerQuoteRequest(q, mealid, limitAmount, "", personalInsuredJSON);
|
|
|
|
|
+ //报价第一次
|
|
|
|
|
+ decryptData = req.quote(qr, h);
|
|
|
|
|
+ //处理重复投保返回终保日期的
|
|
|
|
|
+ DuplQuoteResult duplQuoteResult = handleQuoteErrors(decryptData, q);
|
|
|
|
|
+ if (duplQuoteResult.dupl()) {
|
|
|
|
|
+ qr = new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON);
|
|
|
|
|
+ decryptData = req.quote(qr, h);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理报价响应各种结果
|
|
|
|
|
+ HtCrawlerQuoteResponse.DataDTO data = resolveQuoteResponse(duplQuoteResult, decryptData, mealid,
|
|
|
|
|
+ limitAmount, h, personalInsuredJSON);
|
|
|
|
|
+ return new StepResult(data, personalInsuredJSON);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 重构:抽离重新构建PreResult的逻辑(原递归中重新执行prepareQuote的部分)
|
|
|
|
|
+ */
|
|
|
|
|
+ private PreResult rebuildPreResult(QuoteVo q, String cookie, String quotationNo, String errorMsg, Map<String, Object> gsInfo) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 提取新的modelcodexh
|
|
|
|
|
+ Map<String, Object> map = MAPPER.readValue(errorMsg, Map.class);
|
|
|
|
|
+ List<Map<String, String>> list = (List) map.get("carModelList");
|
|
|
|
|
+ String newModelCodexh = list.get(0).get("vehiclecode");
|
|
|
|
|
+
|
|
|
|
|
+ // 重新执行报价预处理流程
|
|
|
|
|
+ AttributionInformationVo attr = q.getOrder().getAttributionInformationVo();
|
|
|
|
|
+ log.info(map.get("unMatchVehicleFrameMessage") + "已重新执行prepareQuote,新modelcodexh:{}", newModelCodexh);
|
|
|
|
|
+ return prepareQuote(attr, gsInfo, q.getCarInfoVo(),
|
|
|
|
|
+ newModelCodexh, cookie, quotationNo, map);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("重新构建PreResult失败", e);
|
|
|
|
|
+ throw new SystemException("重新获取车型信息失败", e.getMessage());
|
|
|
}
|
|
}
|
|
|
- throw new SystemException("报价失败");
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private String extractMealId(String body) {
|
|
private String extractMealId(String body) {
|
|
@@ -661,10 +692,6 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if (decryptData.contains("传送了车辆过户标志,请确认")) {
|
|
if (decryptData.contains("传送了车辆过户标志,请确认")) {
|
|
|
- //HtCrawlerQuoteResponse.DataDTO dataDTO = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
|
|
- //List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartDTO =
|
|
|
|
|
- // dataDTO.getBasepartdtolist() != null ? dataDTO.getBasepartdtolist().getBasepartdto() : null;
|
|
|
|
|
- //String basePartJSON = buildBasePartJSON(basePartDTO==null?new ArrayList<>():basePartDTO);
|
|
|
|
|
Pattern pattern = Pattern.compile(TRANSFER_FLAG.pattern());
|
|
Pattern pattern = Pattern.compile(TRANSFER_FLAG.pattern());
|
|
|
Matcher matcher = pattern.matcher(decryptData);
|
|
Matcher matcher = pattern.matcher(decryptData);
|
|
|
String transferFlag = "";
|
|
String transferFlag = "";
|
|
@@ -672,82 +699,32 @@ public class HuaTaiCrawlerRequestImpl implements HuaTaiCrawlerRequest {
|
|
|
decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount+","+transferFlag, "", personalInsuredJSON), h);
|
|
decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount+","+transferFlag, "", personalInsuredJSON), h);
|
|
|
return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
|
|
return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
|
|
|
}
|
|
}
|
|
|
- if (!decryptData.contains("录入的校验码有误") && decryptData.contains("erroeInfo") && !duplQuoteResult.dupl()) {
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // autocheckcode 可能不准确,重新获取 quote 刷新验证码
|
|
|
|
|
+ if (decryptData.contains("录入的校验码有误")) {
|
|
|
|
|
+ // 必须传空 basePart,接口才会返回新的 basePart 列表(含新 autocheckcode)
|
|
|
|
|
+ String fresh = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
|
|
|
|
|
+ return resolveQuoteResponse(duplQuoteResult, fresh, mealid, limitAmount, h, personalInsuredJSON);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (decryptData.contains("erroeInfo")) {
|
|
|
|
|
+ log.error("报价失败: {}", decryptData);
|
|
|
log.error("报价失败: {}", convertResponseMsg(decryptData));
|
|
log.error("报价失败: {}", convertResponseMsg(decryptData));
|
|
|
throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
|
|
throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
|
|
|
}
|
|
}
|
|
|
HtCrawlerQuoteResponse.DataDTO data = null;
|
|
HtCrawlerQuoteResponse.DataDTO data = null;
|
|
|
data = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
|
|
data = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
|
|
|
|
|
- if (data.getApplicationdto() != null && !decryptData.contains("车损险保额不能高于")) return data;
|
|
|
|
|
|
|
+ if (data.getApplicationdto() != null) return data;
|
|
|
|
|
|
|
|
List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartDTO =
|
|
List<HtCrawlerQuoteResponse.DataDTO.BasePartDTOListDTO.BasePartDTO> basePartDTO =
|
|
|
data.getBasepartdtolist() != null ? data.getBasepartdtolist().getBasepartdto() : null;
|
|
data.getBasepartdtolist() != null ? data.getBasepartdtolist().getBasepartdto() : null;
|
|
|
- if ((basePartDTO == null || basePartDTO.isEmpty()) && !decryptData.contains("车损险保额不能高于")) throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
|
|
|
|
|
|
|
+ if ((basePartDTO == null || basePartDTO.isEmpty())) throw new SystemException(ERR_PREFIX + convertResponseMsg(decryptData));
|
|
|
|
|
|
|
|
- for (int i = 0; i < MAX_RETRIES; i++) {
|
|
|
|
|
- String basePartJSON = buildBasePartJSON(basePartDTO);
|
|
|
|
|
|
|
+ String basePartJSON = buildBasePartJSON(basePartDTO);
|
|
|
|
|
+ if (StringUtils.isNotBlank(basePartJSON)) {
|
|
|
decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, basePartJSON, personalInsuredJSON), h);
|
|
decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, basePartJSON, personalInsuredJSON), h);
|
|
|
- log.info("resolveQuoteResponse attempt {}/{}: {}", i + 1, MAX_RETRIES, decryptData);
|
|
|
|
|
-
|
|
|
|
|
- if (decryptData.contains("TRANS_MESSAGE") && decryptData.contains("终保日期")) {
|
|
|
|
|
- Map<String, String> map = JSONObject.parseObject(decryptData, Map.class);
|
|
|
|
|
- if (map.containsKey("TRANS_MESSAGE") && map.get("TRANS_MESSAGE").contains("交强")) {
|
|
|
|
|
- Matcher m = PAT_END_DATE2.matcher(decryptData);
|
|
|
|
|
- if (m.find()) {
|
|
|
|
|
- String jiaoqiang_startDate = m.group(1);
|
|
|
|
|
- log.info("报价响应结果CI,终保日期{}", jiaoqiang_startDate);
|
|
|
|
|
- duplQuoteResult.q().getCiRiskInfoVo().setStartDate(jiaoqiang_startDate + ":00");
|
|
|
|
|
- LocalDateTime dt = LocalDateTime.parse(jiaoqiang_startDate.replace(" ", "T"), DateTimeFormatter.ofPattern(DATE_FMT_T));
|
|
|
|
|
- String newEnd = dt.plusYears(1).format(DateTimeFormatter.ofPattern(DATE_FMT));
|
|
|
|
|
- duplQuoteResult.q().getCiRiskInfoVo().setEndDate(newEnd);
|
|
|
|
|
- decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
|
|
|
|
|
- return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- if (map.containsKey("TRANS_MESSAGE") && map.get("TRANS_MESSAGE").contains("商业")) {
|
|
|
|
|
- Matcher m = PAT_END_DATE2.matcher(decryptData);
|
|
|
|
|
- if (m.find()) {
|
|
|
|
|
- String chesun_startDate = m.group(1);
|
|
|
|
|
- log.info("报价响应结果BI,终保日期{}", chesun_startDate);
|
|
|
|
|
- duplQuoteResult.q().getBiRiskInfoVo().setStartDate(chesun_startDate);
|
|
|
|
|
- LocalDateTime dt = LocalDateTime.parse(chesun_startDate.replace(" ", "T"), DateTimeFormatter.ofPattern(DATE_FMT_T));
|
|
|
|
|
- String newEnd = dt.plusYears(1).format(DateTimeFormatter.ofPattern(DATE_FMT));
|
|
|
|
|
- duplQuoteResult.q().getBiRiskInfoVo().setEndDate(newEnd);
|
|
|
|
|
- decryptData = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
|
|
|
|
|
- return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- HtCrawlerQuoteResponse.DataDTO result = null;
|
|
|
|
|
- try {
|
|
|
|
|
- result = JSONObject.parseObject(decryptData, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- throw new RuntimeException(decryptData);
|
|
|
|
|
- }
|
|
|
|
|
- if (result != null && result.getApplicationdto() != null) {
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // autocheckcode 可能不准确,重新获取 quote 刷新验证码
|
|
|
|
|
- if (decryptData.contains("录入的校验码有误") && i < MAX_RETRIES - 1) {
|
|
|
|
|
- log.warn("验证码 校验失败,重新获取 刷新验证码 (尝试 {}/{})", i + 1, MAX_RETRIES);
|
|
|
|
|
- // 必须传空 basePart,接口才会返回新的 basePart 列表(含新 autocheckcode)
|
|
|
|
|
- String fresh = req.quote(new HtCrawlerQuoteRequest(duplQuoteResult.q(), mealid, limitAmount, "", personalInsuredJSON), h);
|
|
|
|
|
- result = JSONObject.parseObject(fresh, HtCrawlerQuoteResponse.DataDTO.class);
|
|
|
|
|
- if (result != null && result.getApplicationdto() != null) {
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
- // 用新的 basePart 列表更新 list,下一轮循环会自动重新 buildBasePartJSON
|
|
|
|
|
- basePartDTO = result != null && result.getBasepartdtolist() != null
|
|
|
|
|
- ? result.getBasepartdtolist().getBasepartdto() : null;
|
|
|
|
|
- if (basePartDTO == null || basePartDTO.isEmpty()) {
|
|
|
|
|
- return result != null ? result : data;
|
|
|
|
|
- }
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- return result != null ? result : data;
|
|
|
|
|
|
|
+ return resolveQuoteResponse(duplQuoteResult, decryptData, mealid, limitAmount, h, personalInsuredJSON);
|
|
|
}
|
|
}
|
|
|
return data;
|
|
return data;
|
|
|
}
|
|
}
|