|
@@ -436,84 +436,69 @@ 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();
|
|
|
|
|
PreResult currentPre = pre;
|
|
PreResult currentPre = pre;
|
|
|
- while (modelCodeRetryCount < MAX_MODEL_CODE_RETRY) {
|
|
|
|
|
- String decryptData = "";
|
|
|
|
|
- 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);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ String decryptData = "";
|
|
|
|
|
+ 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);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理报价响应各种结果
|
|
|
|
|
+ HtCrawlerQuoteResponse.DataDTO data = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ data = resolveQuoteResponse(duplQuoteResult, decryptData, mealid,
|
|
|
|
|
+ limitAmount, h, personalInsuredJSON);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.info("车型异常或其他错误的报价结果: {}", decryptData);
|
|
|
|
|
+ decryptData = e.getMessage();
|
|
|
|
|
+ // 检测modelcodexh不在平台车型范围内的异常在这里处理,需要重走新查车型流程再报价
|
|
|
|
|
+ if (decryptData.contains("errrorFlag") && decryptData.contains("carChange")) {
|
|
|
|
|
|
|
|
- // 处理可能的录入的校验码有误
|
|
|
|
|
- HtCrawlerQuoteResponse.DataDTO data = null;
|
|
|
|
|
|
|
+ // 提取新的modelcodexh
|
|
|
|
|
+ Map<String, Object> map = null;
|
|
|
try {
|
|
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);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ map = MAPPER.readValue(decryptData, Map.class);
|
|
|
|
|
+ } catch (JsonProcessingException ex) {
|
|
|
|
|
+ throw new RuntimeException(ex);
|
|
|
}
|
|
}
|
|
|
- return new StepResult(data, personalInsuredJSON);
|
|
|
|
|
|
|
+ List<Map<String, String>> list = (List)map.get("carModelList");
|
|
|
|
|
+ String newModelCodexh = list.get(0).get("vehiclecode");
|
|
|
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- modelCodeRetryCount++;
|
|
|
|
|
- if (modelCodeRetryCount >= MAX_MODEL_CODE_RETRY) {
|
|
|
|
|
- throw new SystemException(decryptData);
|
|
|
|
|
|
|
+ // 重新执行报价预处理流程
|
|
|
|
|
+ AttributionInformationVo attr = q.getOrder().getAttributionInformationVo();
|
|
|
|
|
+ log.info(map.get("unMatchVehicleFrameMessage")+"已重新执行prepareQuote,新modelcodexh:{}", newModelCodexh);
|
|
|
|
|
+ try {
|
|
|
|
|
+ currentPre = prepareQuote(attr, gsInfo, q.getCarInfoVo(),
|
|
|
|
|
+ newModelCodexh, cookie, quotationNo, map);
|
|
|
|
|
+ } catch (Exception ex) {
|
|
|
|
|
+ throw new RuntimeException(ex);
|
|
|
}
|
|
}
|
|
|
- // 重试前短暂休眠,避免高频请求
|
|
|
|
|
- sleep(SHORT_DELAY_MS);
|
|
|
|
|
|
|
+ executeQuoteSteps(q, quotationNo, dto, cookie, currentPre, gsInfo);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new SystemException(decryptData);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- throw new SystemException("报价失败");
|
|
|
|
|
|
|
+ return new StepResult(data, personalInsuredJSON);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private String extractMealId(String body) {
|
|
private String extractMealId(String body) {
|
|
@@ -661,10 +646,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 +653,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;
|
|
|
}
|
|
}
|