wanghao 4 місяців тому
батько
коміт
f9b5448304

+ 8 - 0
tenant/insurance/quotation-huanong/src/main/java/com/jzg/quotation/huanong/crawler/constant/enums/JiaYiXianProduct.java

@@ -36,6 +36,14 @@ public enum JiaYiXianProduct {
             new CoverageConfig("F27002", "附加团体意外伤害医疗保险条款", "0008", "意外伤害医疗保险责任", 0.24, "1000", "0.1万元/座", "每次事故免赔300后80%比例赔付", false),
             new CoverageConfig("F27001", "附加团体意外伤害住院津贴保险条款", "0032", "意外伤害住院津贴保险责任", 0.2, "10", "0.001万元/座", "10元/天/座", true)
     )),
+    ANXIANG_260("260", "安享驾乘(260)", true, Arrays.asList(
+            new CoverageConfig("Z27096-1", "交通出行团体意外伤害保险C款条款", "0955", "必选责任:意外伤害身故保险责任", 0.06, "30000", "3.0万元/座", " ", false),
+            new CoverageConfig("Z27096-2", "交通出行团体意外伤害保险C款条款", "0956", "可选责任:意外伤害伤残保险责任", 0.04, "30000", "3.0万元/座", " ", false),
+            new CoverageConfig("F27002", "附加团体意外伤害医疗保险条款", "0008", "意外伤害医疗保险责任", 0.24, "1000", "0.1万元/座", "每次事故免赔300后80%比例赔付", false),
+            new CoverageConfig("F27001", "附加团体意外伤害住院津贴保险条款", "0032", "意外伤害住院津贴保险责任", 0.2, "10", "0.001万元/座", "10元/天/座", true),
+            new CoverageConfig("F27047-5", "附加辅助金保险条款", "0094", "家庭辅助金", 0.02, "10", "20000", "2.0万元/座", true),
+            new CoverageConfig("F27048-6", "附加救护车车费保险条款", "0095", "救护车费用", 0.1, "10", "2000", "0.2万元/座", true)
+    )),
     ANXIANG_240("092", "好运连连(240)", true, Arrays.asList(
             new CoverageConfig("Z27096-1", "交通出行团体意外伤害保险C款条款", "0955", "必选责任:意外伤害身故保险责任", 0.06, "30000", "3.0万元/座", " ", false),
             new CoverageConfig("Z27096-2", "交通出行团体意外伤害保险C款条款", "0956", "可选责任:意外伤害伤残保险责任", 0.04, "30000", "3.0万元/座", " ", false),

+ 4 - 2
tenant/insurance/quotation-huanong/src/main/java/com/jzg/quotation/huanong/crawler/entity/request/HuaNongCrawlerActualValueRequestRequest.java

@@ -60,8 +60,10 @@ public class HuaNongCrawlerActualValueRequestRequest implements HuaNongHeadReque
         this.motorTypeCode = carInfoVo.getCarKindCode();
         this.registerDate = TimeProcessing.dateToDateTime(carInfoVo.getRegisterDate());
         this.loginCom = loginCom;
-        this.isNewEnergyFlag = false;
-        this.energyType = carInfoVo.getEnergyTypeCode();
+        // 根据车型查询返回的 energyTypes 判断是否新能源车(0=燃油,4=其他混动,其他=新能源)
+        String energyTypes = carModelDTO != null && carModelDTO.getFullCarData() != null ? carModelDTO.getFullCarData().getEnergyTypes() : null;
+        this.isNewEnergyFlag = energyTypes != null && !"0".equals(energyTypes) && !"4".equals(energyTypes);
+        this.energyType = this.isNewEnergyFlag ? "1" : "0";
     }
 
 }

+ 40 - 9
tenant/insurance/quotation-huanong/src/main/java/com/jzg/quotation/huanong/crawler/entity/request/HuaNongCrawlerQuotedPriceRequestRequest.java

@@ -225,8 +225,10 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
             this.D4ListDataOld = buildD4ListDataOldList();
             this.newEnergyAmountListData = buildNewEnergyAmountListData();
             this.amountListData = buildAmountListData();
-            // 险种
-            this.contract = ContractDTO.build(quoteVo.getCiRiskInfoVo(), quoteVo.getBiRiskInfoVo(), quoteVo.getKindInfoVo(), quoteVo.getInsuredPersonInfo());
+            // 险种:根据车型查询返回的 energyTypes 判断是否新能源车(0=燃油,4=其他混动,其他=新能源)
+            String energyTypes = carModelDTO != null && carModelDTO.getFullCarData() != null ? carModelDTO.getFullCarData().getEnergyTypes() : null;
+            boolean isNewEnergy = energyTypes != null && !"0".equals(energyTypes) && !"4".equals(energyTypes);
+            this.contract = ContractDTO.build(quoteVo.getCiRiskInfoVo(), quoteVo.getBiRiskInfoVo(), quoteVo.getKindInfoVo(), quoteVo.getInsuredPersonInfo(), isNewEnergy);
             // 人员
             this.customer = CustomerDTO.build(quoteVo.getPolicyHolderInfo(), quoteVo.getInsuredPersonInfo(), quoteVo.getOwnersInfo(), this.saleInfo.agentCode, this.saleInfo.comCode);
         }
@@ -792,7 +794,9 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
                     this.pickUpCarFlag = false;
                     this.plateColorCode = "";
                     this.plateNo = carInfoVo.getLicenseNo();
-                    this.isNewEnergyFlag = carInfoVo.isNewEnergyMark();
+                    // 根据车型查询返回的 energyTypes 判断是否新能源车(0=燃油,4=其他混动,其他=新能源)
+                    String energyTypes = fullCarDataDTO != null ? fullCarDataDTO.getEnergyTypes() : null;
+                    this.isNewEnergyFlag = energyTypes != null && !"0".equals(energyTypes) && !"4".equals(energyTypes);
 
                     if (this.isNewEnergyFlag) {
                         this.plateType = "52";
@@ -1974,13 +1978,14 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
                 return contractDTO;
             }
 
-            private static ContractDTO getBiContractDTO(RiskInfoVo biRiskInfoVo, List<KindInfoVo> kindInfoVo, String isAloneCI, String relatedType) {
-                ContractMainDTO bi = new ContractMainDTO(biRiskInfoVo, "0510", "BI", isAloneCI, relatedType);
+            private static ContractDTO getBiContractDTO(RiskInfoVo biRiskInfoVo, List<KindInfoVo> kindInfoVo, String isAloneCI, String relatedType, boolean isNewEnergy) {
+                String riskCode = isNewEnergy ? "0515" : "0510";
+                ContractMainDTO bi = new ContractMainDTO(biRiskInfoVo, riskCode, "BI", isAloneCI, relatedType);
                 ContractDTO contractDTO = new ContractDTO();
                 bi.setBImark(false);
                 contractDTO.setContractMain(bi);
                 List<CoverageDTO> coverageDTOS = kindInfoVo.stream()
-                        .map(kind -> new CoverageDTO(biRiskInfoVo, kind))
+                        .map(kind -> new CoverageDTO(biRiskInfoVo, kind, isNewEnergy))
                         .toList();
                 contractDTO.setTax(new TaxDTO());
                 contractDTO.setPlatFormMessage(new PlatFormMessageDTO());
@@ -1990,7 +1995,7 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
             }
 
 
-            private static List<ContractDTO> build(RiskInfoVo ciRiskInfoVo, RiskInfoVo biRiskInfoVo, List<KindInfoVo> kindInfoVo, CustomerInfoVo insuredPersonInfo) {
+            private static List<ContractDTO> build(RiskInfoVo ciRiskInfoVo, RiskInfoVo biRiskInfoVo, List<KindInfoVo> kindInfoVo, CustomerInfoVo insuredPersonInfo, boolean isNewEnergy) {
                 List<ContractDTO> contractDTOList = new ArrayList<>();
                 String isAloneCI;
                 String relatedType;
@@ -2011,7 +2016,7 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
                         });
                 Optional.ofNullable(biRiskInfoVo)
                         .ifPresent(x -> {
-                            contractDTOList.add(getBiContractDTO(x, kindInfoVo, isAloneCI, relatedType));
+                            contractDTOList.add(getBiContractDTO(x, kindInfoVo, isAloneCI, relatedType, isNewEnergy));
                         });
 
                 return contractDTOList;
@@ -2433,6 +2438,8 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
 
             @Data
             public static class PlatFormMessageDTO {
+                @JsonProperty("lastPolicyExpireDate")
+                private String lastPolicyExpireDate;
                 @JsonProperty("answer")
                 private String answer;
                 @JsonProperty("basePremium")
@@ -2843,6 +2850,10 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
 
 
                 private CoverageDTO(RiskInfoVo biRiskInfoVo, KindInfoVo kind) {
+                    this(biRiskInfoVo, kind, false);
+                }
+
+                private CoverageDTO(RiskInfoVo biRiskInfoVo, KindInfoVo kind, boolean isNewEnergy) {
                     this.amount = kind.getAmount();
                     this.basePremium = 0;
                     this.commission = 0;
@@ -2860,7 +2871,7 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
                     this.expiryDate = biRiskInfoVo.getEndDate();
                     this.flag = "";
                     this.kindCode = kind.getKindCode();
-                    this.kindName = kind.getKindName();
+                    this.kindName = getKindName(kind.getKindCode(), kind.getKindName(), isNewEnergy);
                     this.kindNo = 0;
                     this.kindType = "";
                     this.modeCode = "";
@@ -2890,6 +2901,26 @@ public class HuaNongCrawlerQuotedPriceRequestRequest implements HuaNongHeadReque
                     this.optNotDeductibleFlag = 0;
                     this.ductibleRate = "";
                 }
+
+                private String getKindName(String kindCode, String defaultKindName, boolean isNewEnergy) {
+                    if (!isNewEnergy) {
+                        return defaultKindName;
+                    }
+                    return switch (kindCode) {
+                        case "A" -> "新能源汽车损失保险";
+                        case "B" -> "新能源汽车第三者责任保险";
+                        case "D3" -> "新能源汽车车上人员责任保险(驾驶员)";
+                        case "D4" -> "新能源汽车车上人员责任保险(乘客)";
+                        case "SY_FJ_YBW1" -> "附加医保外医疗费用责任险(新能源汽车第三者责任保险)";
+                        case "TY1" -> "附加新能源汽车增值服务特约条款(道路救援服务)";
+                        case "TY2" -> "附加新能源汽车增值服务特约条款(车辆安全检测)";
+                        case "TY3" -> "附加新能源汽车增值服务特约条款(代为驾驶服务)";
+                        case "TY4" -> "附加新能源汽车增值服务特约条款(代为送检服务)";
+                        case "MJ1" -> "附加绝对免赔率特约险(新能源汽车损失保险)";
+                        case "MJ2" -> "附加绝对免赔率特约险(新能源汽车第三者责任保险)";
+                        default -> defaultKindName;
+                    };
+                }
             }
         }
 

+ 258 - 12
tenant/insurance/quotation-huanong/src/main/java/com/jzg/quotation/huanong/crawler/service/impl/HuaNongCrawlerRequestImpl.java

@@ -9,10 +9,12 @@ import com.jzg.commons.entity.quote.vo.aggregated.*;
 import com.jzg.commons.entity.quote.vo.base.LoginBase;
 import com.jzg.commons.exception.SystemException;
 import com.jzg.commons.util.StringUtils;
+import com.jzg.commons.entity.quote.vo.identify.ReinsuranceCaptchaVo;
 import com.jzg.quotation.commons.annotation.QuoteCrawlerService;
 import com.jzg.quotation.commons.constant.InsuranceCode;
 import com.jzg.quotation.commons.entity.DetectLoginRequest;
 import com.jzg.quotation.commons.filter.CarModelsFilterUtils;
+import com.jzg.quotation.commons.service.ExteriorUtilsRequest;
 import com.jzg.quotation.commons.standard.conversion.ConfigureParametersConversion;
 import com.jzg.quotation.commons.utils.TimeProcessing;
 import com.jzg.quotation.huanong.crawler.build.HuaNongCrawlerQuoteResultsVoBuild;
@@ -38,6 +40,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.http.HttpHeaders;
 
 import java.time.Duration;
+import java.time.LocalDateTime;
 import java.util.*;
 
 @QuoteCrawlerService(InsuranceCode.INSURANCE_HNIC)
@@ -53,6 +56,7 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
     private final HuaNongCrawlerQuoteProcessService huaNongCrawlerQuoteProcessService;
 
     private final HuaNongCrawlerGetToken huaNongCrawlerGetToken;
+    private final ExteriorUtilsRequest exteriorUtilsRequest;
 
     @Override
     public void login(LoginBase loginBase) {
@@ -123,6 +127,13 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
                     huaNongCrawlerQuotedPriceResponse,
                     httpHeaders);
         }
+        // 处理转保验证码
+        if ("0".equals(huaNongCrawlerQuotedPriceResponse.getHead().getReturnCode())) {
+            huaNongCrawlerQuotedPriceResponse = handleTransferVerificationCode(
+                    huaNongCrawlerQuotedPriceRequest,
+                    huaNongCrawlerQuotedPriceResponse,
+                    httpHeaders);
+        }
         // 检查报价异常
         checkQuoteError(huaNongCrawlerQuotedPriceResponse);
 
@@ -138,9 +149,140 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
         return quoteResultsVo;
     }
 
+    /**
+     * 处理转保验证码逻辑
+     * 检测到转保验证码时,OCR识别后回填参数并重新报价
+     *
+     * @param request     报价请求
+     * @param response    报价响应
+     * @param httpHeaders 请求头
+     * @return 处理后的报价响应
+     */
+    private HuaNongCrawlerQuotedPriceResponse handleTransferVerificationCode(
+            HuaNongCrawlerQuotedPriceRequestRequest request,
+            HuaNongCrawlerQuotedPriceResponse response,
+            HttpHeaders httpHeaders) {
+
+        if (response == null || response.getBusinessData() == null) {
+            return response;
+        }
+
+        boolean hasTransferCaptcha = hasTransferVerificationCode(response);
+        if (!hasTransferCaptcha) {
+            return response;
+        }
+
+        log.info("检测到转保验证码,开始处理");
+
+        String ciCaptcha = null;
+        String biCaptcha = null;
+
+        List<HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO> contractList = response.getBusinessData().getContract();
+        for (HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract : contractList) {
+            if (contract.getPlatFormMessage() == null) {
+                continue;
+            }
+
+            String checkCode = contract.getPlatFormMessage().getCheckCode();
+            if (!StringUtils.hasText(checkCode)) {
+                continue;
+            }
+
+            String querySequenceNo = contract.getPlatFormMessage().getQuerySequenceNo();
+            String queryDate = contract.getPlatFormMessage().getQueryDate();
+            HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO.PlatFormMessageDTO platFormMessage = contract.getPlatFormMessage();
+
+            String captchaResult = identifyCaptcha(checkCode);
+
+            String riskCode = contract.getContractMain().getRiskCode();
+            boolean isCi = "0507".equals(riskCode);
+            boolean isBi = "0510".equals(riskCode) || "0515".equals(riskCode);
+
+            if (isCi) {
+                ciCaptcha = captchaResult;
+            } else if (isBi) {
+                biCaptcha = captchaResult;
+            }
+
+            updateRequestWithCaptcha(request, riskCode, captchaResult, querySequenceNo, queryDate, platFormMessage);
+        }
+
+        ReinsuranceCaptchaVo reinsuranceCaptchaVo = new ReinsuranceCaptchaVo(ciCaptcha, biCaptcha);
+        exteriorUtilsRequest.reinsuranceCaptchaIdentify(reinsuranceCaptchaVo);
+
+        log.info("转保验证码处理完成,交强险验证码:{},商业险验证码:{}", ciCaptcha, biCaptcha);
+
+        return huaNongCrawlerRequestComponent.quotedPrice(request, httpHeaders);
+    }
+
+    private boolean hasTransferVerificationCode(HuaNongCrawlerQuotedPriceResponse response) {
+        if (response == null || response.getBusinessData() == null ||
+                response.getBusinessData().getContract() == null) {
+            return false;
+        }
+
+        if (StringUtils.hasText(response.getComeCode())) {
+            return false;
+        }
+
+        for (HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract : response.getBusinessData().getContract()) {
+            if (contract.getPlatFormMessage() != null &&
+                    StringUtils.hasText(contract.getPlatFormMessage().getCheckCode())) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private String identifyCaptcha(String checkCode) {
+        String result = exteriorUtilsRequest.captchaIdentify(checkCode);
+        if (result != null) {
+            result = result.replace('0', 'O');
+        }
+        return result;
+    }
+
+    private void updateRequestWithCaptcha(HuaNongCrawlerQuotedPriceRequestRequest request,
+                                          String riskCode,
+                                          String captchaResult,
+                                          String querySequenceNo,
+                                          String queryDate,
+                                          HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO.PlatFormMessageDTO responsePlatFormMessage) {
+
+        request.getBusinessData().getContract().stream()
+                .filter(dto -> riskCode.equals(dto.getContractMain().getRiskCode()))
+                .findFirst()
+                .ifPresent(dto -> {
+                    dto.getContractMain().setCheckFlag("Check");
+                    dto.getContractMain().setRenewalFlag("-1");
+                    dto.getContractMain().setQuerySequenceNo(querySequenceNo);
+                    dto.getContractMain().setProductionDate(TimeProcessing.nowDateTime());
+
+                    HuaNongCrawlerQuotedPriceRequestRequest.BusinessDataDTO.ContractDTO.PlatFormMessageDTO platFormMessage = dto.getPlatFormMessage();
+                    if (platFormMessage == null) {
+                        platFormMessage = new HuaNongCrawlerQuotedPriceRequestRequest.BusinessDataDTO.ContractDTO.PlatFormMessageDTO();
+                        dto.setPlatFormMessage(platFormMessage);
+                    }
+
+                    platFormMessage.setQueryDate(queryDate);
+                    platFormMessage.setQuerySequenceNo(querySequenceNo);
+                    platFormMessage.setCheckCodeRe(captchaResult);
+
+                    if (responsePlatFormMessage != null) {
+                        platFormMessage.setCheckCode(responsePlatFormMessage.getCheckCode());
+                        platFormMessage.setCiReinsureMessage(responsePlatFormMessage.getCiReinsureMessage());
+                        platFormMessage.setBiReinsureMessage(responsePlatFormMessage.getBiReinsureMessage());
+                        platFormMessage.setCiReinsureEndDate(responsePlatFormMessage.getCiReinsureEndDate());
+                        platFormMessage.setBiReinsureEndDate(responsePlatFormMessage.getBiReinsureEndDate());
+                        platFormMessage.setLastPolicyExpireDate(responsePlatFormMessage.getLastPolicyExpireDate());
+                    }
+                });
+    }
+
     /**
      * 处理重复投保逻辑
-     * 检测到重复投保时调整日期后重试,重试后仍重复投保则抛出异常
+     * 检测到重复投保时调整日期后重试,重试后仍重复投保则日期再向后推迟一天重试,第二次重试后仍重复投保则返回结果
      *
      * @param request     报价请求
      * @param response    报价响应
@@ -163,7 +305,6 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
 
         boolean hasDuplicateInsurance = false;
 
-        // 第一次遍历:检查是否有需要处理的重复投保
         for (HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract : contractList) {
             if (contract.getPlatFormMessage() == null) {
                 continue;
@@ -172,7 +313,6 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
             String ciReinsureMsg = contract.getPlatFormMessage().getCiReinsureMessage();
             String biReinsureMsg = contract.getPlatFormMessage().getBiReinsureMessage();
 
-            // 同时检查"重复投保"和"终保日期"
             boolean isCiDuplicate = StringUtils.hasText(ciReinsureMsg) &&
                     (ciReinsureMsg.contains("重复投保") || ciReinsureMsg.contains("终保日期"));
             boolean isBiDuplicate = StringUtils.hasText(biReinsureMsg) &&
@@ -188,11 +328,15 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
             return response;
         }
 
-        // 处理重复投保:调整日期并重试
         response = processDuplicateInsurance(request, response, httpHeaders);
 
-        // 检查重试后是否仍然重复投保
-        return checkAndHandleRemainingDuplicate(response);
+        boolean stillDuplicate = hasDuplicateInsurance(response);
+        if (stillDuplicate) {
+            log.info("第一次重试后仍存在重复投保,日期向后推迟一天进行第二次重试");
+            response = processDuplicateInsuranceWithOneMoreDay(request, response, httpHeaders);
+        }
+
+        return checkAndHandleRemainingDuplicate(response, false);
     }
 
     private HuaNongCrawlerQuotedPriceResponse processDuplicateInsurance(
@@ -213,7 +357,7 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
                     StringUtils.hasText(ciReinsureMsg) &&
                     (ciReinsureMsg.contains("重复投保") || ciReinsureMsg.contains("终保日期"));
 
-            boolean needAdjustBi = "0510".equals(riskCode) &&
+            boolean needAdjustBi = ("0510".equals(riskCode) || "0515".equals(riskCode)) &&
                     StringUtils.hasText(biReinsureMsg) &&
                     (biReinsureMsg.contains("重复投保") || biReinsureMsg.contains("终保日期"));
 
@@ -225,6 +369,102 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
         return huaNongCrawlerRequestComponent.quotedPrice(request, httpHeaders);
     }
 
+    private boolean hasDuplicateInsurance(HuaNongCrawlerQuotedPriceResponse response) {
+        if (response == null || response.getBusinessData() == null ||
+                response.getBusinessData().getContract() == null) {
+            return false;
+        }
+
+        for (HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract : response.getBusinessData().getContract()) {
+            if (contract.getPlatFormMessage() == null) {
+                continue;
+            }
+
+            String ciReinsureMsg = contract.getPlatFormMessage().getCiReinsureMessage();
+            String biReinsureMsg = contract.getPlatFormMessage().getBiReinsureMessage();
+
+            boolean isCiDuplicate = StringUtils.hasText(ciReinsureMsg) &&
+                    (ciReinsureMsg.contains("重复投保") || ciReinsureMsg.contains("终保日期"));
+            boolean isBiDuplicate = StringUtils.hasText(biReinsureMsg) &&
+                    (biReinsureMsg.contains("重复投保") || biReinsureMsg.contains("终保日期"));
+
+            if (isCiDuplicate || isBiDuplicate) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private HuaNongCrawlerQuotedPriceResponse processDuplicateInsuranceWithOneMoreDay(
+            HuaNongCrawlerQuotedPriceRequestRequest request,
+            HuaNongCrawlerQuotedPriceResponse response,
+            HttpHeaders httpHeaders) {
+
+        for (HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract : response.getBusinessData().getContract()) {
+            if (contract.getPlatFormMessage() == null) {
+                continue;
+            }
+
+            String riskCode = contract.getContractMain().getRiskCode();
+            String ciReinsureMsg = contract.getPlatFormMessage().getCiReinsureMessage();
+            String biReinsureMsg = contract.getPlatFormMessage().getBiReinsureMessage();
+
+            boolean needAdjustCi = "0507".equals(riskCode) &&
+                    StringUtils.hasText(ciReinsureMsg) &&
+                    (ciReinsureMsg.contains("重复投保") || ciReinsureMsg.contains("终保日期"));
+
+            boolean needAdjustBi = ("0510".equals(riskCode) || "0515".equals(riskCode)) &&
+                    StringUtils.hasText(biReinsureMsg) &&
+                    (biReinsureMsg.contains("重复投保") || biReinsureMsg.contains("终保日期"));
+
+            if (needAdjustCi || needAdjustBi) {
+                adjustPolicyDateWithOneMoreDay(request, riskCode, contract);
+            }
+        }
+
+        return huaNongCrawlerRequestComponent.quotedPrice(request, httpHeaders);
+    }
+
+    private void adjustPolicyDateWithOneMoreDay(HuaNongCrawlerQuotedPriceRequestRequest request,
+                                                 String riskCode, HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract) {
+
+        String lastExpireDate = "";
+
+        if ("0507".equals(riskCode)) {
+            lastExpireDate = contract.getPlatFormMessage().getCiReinsureEndDate();
+        } else if ("0510".equals(riskCode) || "0515".equals(riskCode)) {
+            String biReinsureEndDate = contract.getPlatFormMessage().getBiReinsureEndDate();
+            String lastPolicyExpireDate = contract.getPlatFormMessage().getLastPolicyExpireDate();
+
+            if (StringUtils.hasText(biReinsureEndDate)) {
+                lastExpireDate = biReinsureEndDate;
+            } else if (StringUtils.hasText(lastPolicyExpireDate)) {
+                lastExpireDate = lastPolicyExpireDate;
+            }
+        }
+
+        if (StringUtils.hasText(lastExpireDate)) {
+            lastExpireDate = ensureDateTimeFormat(lastExpireDate);
+            lastExpireDate = plusOneDayDateTime(lastExpireDate);
+
+            String finalLastExpireDate = lastExpireDate;
+            request.getBusinessData().getContract().stream()
+                    .filter(dto -> riskCode.equals(dto.getContractMain().getRiskCode()))
+                    .findFirst()
+                    .ifPresent(dto -> {
+                        dto.getContractMain().setValidDate(finalLastExpireDate);
+                        dto.getContractMain().setExpiryDate(TimeProcessing.minusOneSecondAfterYear(finalLastExpireDate));
+                        dto.getCoverage().get(0).setValidDate(finalLastExpireDate);
+                    });
+        }
+    }
+
+    private String plusOneDayDateTime(String dateTime) {
+        LocalDateTime localDateTime = LocalDateTime.parse(dateTime, TimeProcessing.DATE_TIME_FORMATTER);
+        return localDateTime.plusDays(1).format(TimeProcessing.DATE_TIME_FORMATTER);
+    }
+
     private void adjustPolicyDate(HuaNongCrawlerQuotedPriceRequestRequest request,
                                   String riskCode, HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract) {
 
@@ -233,7 +473,7 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
         if ("0507".equals(riskCode)) {
             // 交强险:优先使用 ciReinsureEndDate
             lastExpireDate = contract.getPlatFormMessage().getCiReinsureEndDate();
-        } else if ("0510".equals(riskCode)) {
+        } else if ("0510".equals(riskCode) || "0515".equals(riskCode)) {
             // 商业险:优先使用 biReinsureEndDate,其次使用 lastPolicyExpireDate
             String biReinsureEndDate = contract.getPlatFormMessage().getBiReinsureEndDate();
             String lastPolicyExpireDate = contract.getPlatFormMessage().getLastPolicyExpireDate();
@@ -256,11 +496,12 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
                     .ifPresent(dto -> {
                         dto.getContractMain().setValidDate(finalLastExpireDate);
                         dto.getContractMain().setExpiryDate(TimeProcessing.minusOneSecondAfterYear(finalLastExpireDate));
+                        dto.getCoverage().get(0).setValidDate(finalLastExpireDate);
                     });
         }
     }
 
-    private HuaNongCrawlerQuotedPriceResponse checkAndHandleRemainingDuplicate(HuaNongCrawlerQuotedPriceResponse response) {
+    private HuaNongCrawlerQuotedPriceResponse checkAndHandleRemainingDuplicate(HuaNongCrawlerQuotedPriceResponse response, boolean throwException) {
         if (response == null || response.getBusinessData() == null ||
                 response.getBusinessData().getContract() == null) {
             return response;
@@ -297,7 +538,11 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
         }
 
         if (errorMsg.length() > 0) {
-            throw new SystemException("重复投保处理失败:" + errorMsg.toString());
+            if (throwException) {
+                throw new SystemException("重复投保处理失败:" + errorMsg.toString());
+            } else {
+                throw new SystemException("重复投保处理后仍存在重复投保,已尽最大努力重试,返回当前结果:{}", errorMsg.toString());
+            }
         }
 
         return response;
@@ -337,11 +582,12 @@ public class HuaNongCrawlerRequestImpl implements HuaNongCrawlerRequest {
     // 处理重复投保
     private HuaNongCrawlerQuotedPriceResponse repeatQuote(HuaNongCrawlerQuotedPriceRequestRequest huaNongCrawlerQuotedPriceRequest, HuaNongCrawlerQuotedPriceResponse.BusinessDataDTO.ContractDTO contract, HttpHeaders httpHeaders) {
         String riskCode = contract.getContractMain().getRiskCode();
-        if ("0510".equals(riskCode)) {
+        if ("0510".equals(riskCode) || "0515".equals(riskCode)) {
             String lastExpireDate = contract.getPlatFormMessage().getLastPolicyExpireDate();
             if (lastExpireDate != null && !lastExpireDate.trim().isEmpty()) {
+                final String finalRiskCode = riskCode;
                 huaNongCrawlerQuotedPriceRequest.getBusinessData().getContract().stream()
-                        .filter(dto -> "0510".equals(dto.getContractMain().getRiskCode()))
+                        .filter(dto -> finalRiskCode.equals(dto.getContractMain().getRiskCode()))
                         .findFirst()
                         .ifPresent(dto -> {
                             dto.getContractMain().setValidDate(lastExpireDate);