wangrq 4 месяцев назад
Родитель
Сommit
94dc72267d

+ 1 - 1
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/build/BoHaiCrawlerQuoteResultsVoBuild.java

@@ -125,7 +125,7 @@ public class BoHaiCrawlerQuoteResultsVoBuild {
         // 交易流水号
         quoteResultsVo.setCompanyOrderNo("");
         // 报价失败提示
-        quoteResultsVo.setErrorMessage("报价失败");
+        quoteResultsVo.setErrorMessage(boHaiQuoteResponse.getHead().getReturnMessage());
         //设置报价状态:
         quoteResultsVo.setQuoteStatusEnum(InsOrderStatusEnum.QUOTE_FAIL);
         return quoteResultsVo;

+ 2 - 2
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/component/BoHaiCrawlerRequestComponent.java

@@ -190,7 +190,7 @@ public class BoHaiCrawlerRequestComponent {
 
                     CrawlerRequestUrlStandard standard = (CrawlerRequestUrlStandard) urlOrStandard;
                     ResponseEntity<String> encryptedResponse = requestComponent.objectPost(
-                            standard.getRequestUrl(boHaiCrawlerProperties.getBaseUrl2()),
+                            standard.getRequestUrl(boHaiCrawlerProperties.getBaseUrl()),
                             boHaiCrawlerEncryptionRequest,
                             String.class,
                             headers
@@ -354,7 +354,7 @@ public class BoHaiCrawlerRequestComponent {
      * @return BoHaiCrawlerCarResponse 车型列表
      */
     public BoHaiCrawlerCarApiResponse car(BoHaiCrawlerCarRequest boHaiCrawlerCarRequest, HttpHeaders headers) {
-        return executeRequest(RequestType.ENCRYPTED, RequestUrl.CAR, boHaiCrawlerCarRequest, BoHaiCrawlerCarApiResponse.class, headers);
+        return executeRequest(RequestType.UNENCRYPTED, RequestUrl.CAR, boHaiCrawlerCarRequest, BoHaiCrawlerCarApiResponse.class, headers);
     }
 
     /**

+ 7 - 7
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/entity/request/BoHaiCrawlerQuotationRequest2.java

@@ -63,7 +63,7 @@ public class BoHaiCrawlerQuotationRequest2 {
         @JSONField(ordinal = 3)
         private List<Insured> insuredList;
         /** 险种集合(商业险/交强险及其条款) */
-        @JSONField(ordinal = 4)
+        @JSONField(ordinal = 4, serialzeFeatures = {SerializerFeature.NotWriteDefaultValue})
         private List<Risk> riskList;
     }
 
@@ -313,7 +313,7 @@ public class BoHaiCrawlerQuotationRequest2 {
 
         /** 排量/功率(L/kW) */
         @JSONField(ordinal = 25)
-        private Double exhaustScale;
+        private String exhaustScale;
 
         /** 注册日期(初登) */
         @JSONField(ordinal = 26)
@@ -329,9 +329,9 @@ public class BoHaiCrawlerQuotationRequest2 {
 
         /** 使用年限 */
         @JSONField(ordinal = 29)
-        private String useYearsDI;
+        private Integer useYearsDI;
 
-        /** 过户标志 */
+        /** 过户标志 “0" 非过户 */
         @JSONField(ordinal = 30)
         private String chgOwnerFlag;
 
@@ -699,7 +699,7 @@ public class BoHaiCrawlerQuotationRequest2 {
         private String nation;
 
         /** 证件签发机关 */
-        @JSONField(ordinal = 25)
+        @JSONField(ordinal = 25,serialzeFeatures = SerializerFeature.WriteMapNullValue)
         private String identifyIssuer;
 
         /** 证件地址 */
@@ -749,7 +749,7 @@ public class BoHaiCrawlerQuotationRequest2 {
         /**
          * 驾驶人数量
          */
-        @JSONField(ordinal = 37)
+        @JSONField(name = "DInsuredCount", ordinal = 37)
         private String DInsuredCount;
 
         /** 是否指定受益人 */
@@ -1014,7 +1014,7 @@ public class BoHaiCrawlerQuotationRequest2 {
         @JSONField(ordinal = 49)
         private String expPricingAdjustValue;
         /** 不浮动费用率 */
-        @JSONField(ordinal = 50)
+        @JSONField(name = "NoneFluctuateFeeRate", ordinal = 50)
         private String NoneFluctuateFeeRate;
     }
     /**

+ 31 - 1
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/entity/request/BoHaiCrawlerVehicleConfirmationReqeust1.java

@@ -212,7 +212,7 @@ public class BoHaiCrawlerVehicleConfirmationReqeust1 implements Serializable {
          * 排气量
          */
         @JsonProperty("displacement")
-        private String displacement;
+        private Double displacement;
 
         /**
          * 功率
@@ -345,6 +345,36 @@ public class BoHaiCrawlerVehicleConfirmationReqeust1 implements Serializable {
          */
         @JsonProperty("PrecisePriceComCode")
         private Boolean precisePriceComCode;
+
+        /**
+         * 车主名称
+         */
+        @JsonProperty("ownerName")
+        private String ownerName;
+
+        /**
+         * 车主证件类型
+         */
+        @JsonProperty("ownerCertificateType")
+        private String ownerCertificateType;
+
+        /**
+         * 车主证件号码
+         */
+        @JsonProperty("ownerCertificateNum")
+        private String ownerCertificateNum;
+
+        /**
+         * 证件类型
+         */
+        @JsonProperty("certificateType")
+        private String certificateType;
+
+        /**
+         * 证件号码
+         */
+        @JsonProperty("certificateNo")
+        private String certificateNo;
     }
 
 

+ 4 - 5
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/service/impl/BoHaiCrawlerQuoteProcessServiceImpl.java

@@ -45,12 +45,12 @@ public class BoHaiCrawlerQuoteProcessServiceImpl implements BoHaiCrawlerQuotePro
     /**
      * Python脚本路径
      */
-    private static final String PYTHON_SCRIPT_PATH = "e:/project/jzg/tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/novel.py";
+    private static final String PYTHON_SCRIPT_PATH = "E:/IdeaProjects/jzg/tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/novel.py";
 
     /**
      * Python解释器路径
      */
-    private static final String PYTHON_EXECUTABLE_PATH = "E:\\project\\memorize_backend\\venv\\Scripts\\python.exe";
+    private static final String PYTHON_EXECUTABLE_PATH = "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/python.exe";
 
     /**
      * Python脚本执行超时时间(秒)
@@ -133,12 +133,11 @@ public class BoHaiCrawlerQuoteProcessServiceImpl implements BoHaiCrawlerQuotePro
         headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
         return headers;*/
         HttpHeaders httpHeaders = new HttpHeaders();
-        httpHeaders.set("Cookie", "HTTPOnly; skin-color=skin-db; Cookie=!uEW94o2278iwLg21yv2qnldjEk8Kb5RsZkOl0FDX8+Mqxb0EGroyfXXQVmrGlnxevDyUYDwsWh2B5iY=; JSESSIONID=0001TTPD95X9DLJB1il0R_O_NhM:3T0NUMVN3E");
+        httpHeaders.set("Cookie", "HTTPOnly; Cookie=!EGmfBaVL8vRhQVm1yv2qnldjEk8KbwtSAPXA04eIJoNmCDYPGJ9wrhISai6LJc/RzChzLWC1R3fADU8=; JSESSIONID=0003Q7K2MvYVNnSRpylGrMlbm0d:-B0CDG8:1RGHVQ8T50:1Q4PVUSPE8");
 
         // 从Redis获取sessionId
         String sessionId = getOrRefreshSessionId();
-
-        if (StringUtils.hasLength(sessionId)) {
+        if (!StringUtils.hasLength(sessionId)) {
             sessionId = getSessionId();
         }
         httpHeaders.set("sessionId", sessionId);

+ 260 - 93
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/service/impl/BoHaiCrawlerRequestImpl.java

@@ -4,12 +4,10 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.google.zxing.NotFoundException;
 import com.jzg.commons.constants.dict.InsOrderStatusEnum;
-import com.jzg.commons.entity.quote.vo.AttributionInformationVo;
-import com.jzg.commons.entity.quote.vo.CustomerInfoVo;
-import com.jzg.commons.entity.quote.vo.KindInfoVo;
-import com.jzg.commons.entity.quote.vo.QuoteVo;
+import com.jzg.commons.entity.quote.vo.*;
 import com.jzg.commons.entity.quote.vo.aggregated.*;
 import com.jzg.commons.entity.quote.vo.base.LoginBase;
+import com.jzg.commons.util.ObjectUtil;
 import com.jzg.quotation.bohai.api.constant.enums.ResponseCode;
 import com.jzg.quotation.bohai.api.entity.BoHaiConfigureParameters;
 import com.jzg.quotation.bohai.api.entity.request.ElectronicPolicyRequest;
@@ -19,6 +17,7 @@ import com.jzg.quotation.bohai.api.entity.request.StatusDocumentsRequest;
 import com.jzg.quotation.bohai.api.entity.response.ElectronicPolicyResponse;
 import com.jzg.quotation.bohai.api.entity.response.StatusDocumentsResponse;
 import com.jzg.quotation.bohai.api.entity.vo.PersonAreaVo;
+import com.jzg.quotation.bohai.api.util.StringSubStringUtils;
 import com.jzg.quotation.bohai.crawler.component.BoHaiCrawlerCacheComponent;
 import com.jzg.quotation.bohai.crawler.component.BoHaiBuildingAttributionInformation;
 import com.jzg.quotation.bohai.crawler.constant.enums.CertifyType;
@@ -40,14 +39,18 @@ import com.jzg.quotation.bohai.crawler.entity.response.*;
 import com.jzg.quotation.bohai.crawler.service.BoHaiCrawlerOrderService;
 import com.jzg.quotation.bohai.crawler.service.BoHaiCrawlerQuoteProcessService;
 import com.jzg.quotation.bohai.crawler.service.BoHaiCrawlerRequest;
+import com.jzg.quotation.commons.utils.DateTimeUtil;
+import com.jzg.quotation.commons.utils.DateUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.http.HttpHeaders;
 import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
 
 import java.io.IOException;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 
@@ -83,8 +86,8 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
      * 说明:E:\project\memorize_backend\venv\Scripts\python.exe   这是我本地的python解释器路径,这个需要修改为你本地的路径
      */
     private static final String TOKEN = PythonExecutor.executeAndGetToken(
-            "E:/project/jzg/tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/novel.py",
-            "E:\\project\\memorize_backend\\venv\\Scripts\\python.exe", 120);
+            "E:/IdeaProjects/jzg/tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/novel.py",
+            "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/python.exe", 120);
 
     /**
      * 登录
@@ -110,37 +113,49 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
     @Override
     public QuoteResultsVo quote(QuoteVo quoteVo) {
         try {
-            // 1.0 获取归属信息和配置参数
-            AttributionInformationVo attributionInformationVo = quoteVo.getOrder().getAttributionInformationVo();
-            HttpHeaders headers = boHaiCrawlerQuoteProcessService.getHeaders(attributionInformationVo.getUsername(), attributionInformationVo.getPassword());
-            String userCode = boHaiCrawlerCacheComponent.getUserCode(attributionInformationVo.getUsername());
-            log.info("userCode:{}", userCode);
-
-            BoHaiCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(
-                    BoHaiCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
-            log.info("parameters参数的值:{}", JSON.toJSONString(parameters));
-
-            // 2.0 车辆查询
-            BoHaiCrawlerCarApiResponse carApiResponse = queryCarInfo(quoteVo, parameters, userCode, headers);
-            log.info("[车辆查询]返回参数的值:{}", JSON.toJSONString(carApiResponse));
-            // 车辆确认
-            BoHaiCrawlerVehicleConfirmationResponse2 confirmationResponse = confirmVehicle(quoteVo, carApiResponse, parameters, headers);
-            log.info("[车辆确认]返回参数的值:{}", JSON.toJSONString(confirmationResponse));
-
-            // 3.0 构建报价请求并发起报价
-            BoHaiCrawlerQuotationRequest2 quotationRequest = buildQuotationRequest(quoteVo, carApiResponse, confirmationResponse);
-            log.info("[报价]请求参数的值:{}", JSON.toJSONString(quotationRequest));
-            BoHaiCrawlerQuotationResponse2 boHaiCrawlerQuotationResponse2 = boHaiCrawlerRequestComponent.quotation(quotationRequest, headers);
-            log.info("[报价]返回参数的值:{}", JSON.toJSONString(boHaiCrawlerQuotationResponse2));
-
-            // 4.0 处理报价结果
-            return handleQuotationResponse(quoteVo, boHaiCrawlerQuotationResponse2);
+            // 执行报价流程
+            return executeQuotation(quoteVo);
         } catch (Exception e) {
             log.error("报价异常", e);
             throw new RuntimeException(e);
         }
     }
 
+    /**
+     * 执行报价流程(通用方法,首次报价和重复报价共用)
+     *
+     * @param quoteVo 报价实体
+     * @return QuoteResultsVo
+     */
+    private QuoteResultsVo executeQuotation(QuoteVo quoteVo) {
+        // 1.0 获取归属信息和配置参数
+        AttributionInformationVo attributionInformationVo = quoteVo.getOrder().getAttributionInformationVo();
+        HttpHeaders headers = boHaiCrawlerQuoteProcessService.getHeaders(attributionInformationVo.getUsername(), attributionInformationVo.getPassword());
+        String userCode = boHaiCrawlerCacheComponent.getUserCode(attributionInformationVo.getUsername());
+        log.info("userCode:{}", userCode);
+
+        BoHaiCrawlerConfigureParameters parameters = ConfigureParametersConversion.conversionEntity(
+                BoHaiCrawlerConfigureParameters.class, attributionInformationVo.getConfigInfo());
+        log.info("parameters参数的值:{}", JSON.toJSONString(parameters));
+
+        // 2.0 车辆查询
+        BoHaiCrawlerCarApiResponse carApiResponse = queryCarInfo(quoteVo, parameters, userCode, headers);
+        log.info("[车辆查询]返回参数的值:{}", JSON.toJSONString(carApiResponse));
+        
+        // 车辆确认
+        BoHaiCrawlerVehicleConfirmationResponse2 confirmationResponse = confirmVehicle(quoteVo, carApiResponse, parameters, headers);
+        log.info("[车辆确认]返回参数的值:{}", JSON.toJSONString(confirmationResponse));
+
+        // 3.0 构建报价请求并发起报价
+        BoHaiCrawlerQuotationRequest2 quotationRequest = buildQuotationRequest(quoteVo, carApiResponse, confirmationResponse);
+        log.info("[报价]请求参数的值:{}", JSON.toJSONString(quotationRequest));
+        BoHaiCrawlerQuotationResponse2 boHaiCrawlerQuotationResponse2 = boHaiCrawlerRequestComponent.quotation(quotationRequest, headers);
+        log.info("[报价]返回参数的值:{}", JSON.toJSONString(boHaiCrawlerQuotationResponse2));
+
+        // 4.0 处理报价结果
+        return handleQuotationResponse(quoteVo, boHaiCrawlerQuotationResponse2);
+    }
+
     /**
      * 车辆查询
      *
@@ -175,7 +190,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
      *
      * @param quoteVo
      * @param carApiResponse
-     * @param currentValue
+     * @param confirmationResponse
      * @return BoHaiCrawlerQuotationRequest2
      */
     private BoHaiCrawlerQuotationRequest2 buildQuotationRequest(QuoteVo quoteVo, BoHaiCrawlerCarApiResponse carApiResponse, BoHaiCrawlerVehicleConfirmationResponse2 confirmationResponse) {
@@ -206,7 +221,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
      *
      * @param quoteVo
      * @param carApiResponse
-     * @param currentValue
+     * @param confirmationResponse
      * @return BoHaiCrawlerQuotationRequest2.BusinessData
      */
     private BoHaiCrawlerQuotationRequest2.BusinessData buildBusinessData(QuoteVo quoteVo, BoHaiCrawlerCarApiResponse carApiResponse, BoHaiCrawlerVehicleConfirmationResponse2 confirmationResponse) {
@@ -254,7 +269,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         mainInfo.setUnderUnit("");
         mainInfo.setIdentifyType("006");
         mainInfo.setIdentifyDetail("00001");
-        mainInfo.setIdentifyCode("");
+        mainInfo.setIdentifyCode(null);
         mainInfo.setIdentifyVip("");
         mainInfo.setComputerIp("");
         mainInfo.setMainCarKindBC("0");
@@ -281,7 +296,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
      *
      * @param quoteVo
      * @param carApiResponse
-     * @param currentValue
+     * @param confirmationResponse
      * @return BoHaiCrawlerQuotationRequest2.CarInfo
      */
     private BoHaiCrawlerQuotationRequest2.CarInfo buildCarInfo(QuoteVo quoteVo, BoHaiCrawlerCarApiResponse carApiResponse, BoHaiCrawlerVehicleConfirmationResponse2 confirmationResponse) {
@@ -296,11 +311,11 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         item.setPureRange("");
         // 燃油类型:A=汽油
         item.setPmFuelType("A");
-        // 验车状态:4=已验
-        item.setCarCheckStatus("4");
-        item.setActualValue(currentValue);
+        // 验车状态: 1=已验
+        item.setCarCheckStatus("1");
+        item.setActualValue("");//设置有值会出现价格实际价格与系统计算价格不一致问题
         item.setOtherNature7BI("0");
-        item.setNegotiatedValue(currentValue);
+        item.setNegotiatedValue("");//设置有值会出现价格实际价格与系统计算价格不一致问题
         // 新车标志:0=非新车
         item.setNewVehicleFlag("0");
         item.setLicenseNo(quoteVo.getCarInfoVo().getLicenseNo());
@@ -309,7 +324,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         item.setVinNo(quoteVo.getCarInfoVo().getVinNo());
         item.setNoLicenseFlag("");
         item.setLicenseColorCode(carApiResponse.getData().getJyCarModelFill().getPlateNoColor());
-        item.setUseNatureCode(quoteVo.getCarInfoVo().getCarNatureCode());
+        item.setUseNatureCode("8A"); // 8A=非营运
         item.setMainCarKindCode("A");
         item.setCarKindCode("A0");
 
@@ -319,12 +334,12 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         // 新车购置价(元)
         item.setPurchasePrice(carApiResponse.getData().getPrpDCarModels().get(0).getPurchasePrice());
         item.setBasePurchasePrice(carApiResponse.getData().getPrpDCarModels().get(0).getPurchasePrice());
-        item.setExhaustScale(Double.parseDouble(carApiResponse.getData().getPrpDCarModels().get(0).getExhaustScale()));
+        item.setExhaustScale(carApiResponse.getData().getPrpDCarModels().get(0).getExhaustScale() == null ? "" : String.valueOf(carApiResponse.getData().getPrpDCarModels().get(0).getExhaustScale()));
         item.setEnrollDate(quoteVo.getCarInfoVo().getRegisterDate());
         item.setUseYearsBI("");
         item.setUseYearsCI(0);
-        item.setUseYearsDI("");
-        item.setChgOwnerFlag(quoteVo.getCarInfoVo().getChgOwnerFlag());
+        item.setUseYearsDI(0);
+        item.setChgOwnerFlag(ObjectUtils.isEmpty(quoteVo.getCarInfoVo().getChgOwnerFlag()) ? "0" : quoteVo.getCarInfoVo().getChgOwnerFlag());
         item.setChgTypeFlag("0");
         //转移登记日期
         item.setChgOwnerDate(quoteVo.getCarInfoVo().getIssueDate());
@@ -340,7 +355,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         item.setMakeDate("");
         // 车辆品牌
         item.setVehicleBrand(carApiResponse.getData().getPrpDCarModels().get(0).getCarBrand());
-        item.setCompleteKerbMass(Integer.parseInt(carApiResponse.getData().getPrpDCarModels().get(0).getCompleteKerbMass()));
+        item.setCompleteKerbMass(ObjectUtils.isEmpty(carApiResponse.getData().getPrpDCarModels().get(0).getCompleteKerbMass()) ? 0 :Integer.parseInt(carApiResponse.getData().getPrpDCarModels().get(0).getCompleteKerbMass()));
         item.setLicenseKindCode(quoteVo.getCarInfoVo().getLicenseKindCode());
         item.setLicenseCategory(quoteVo.getCarInfoVo().getCarTypeCode());
         // 商业险续保标志:0=非续保
@@ -440,12 +455,12 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
 
         // 被保险人
         insuredList.add(createInsured2("2", "", quoteVo.getInsuredPersonInfo().getIdentifyNumber(), "01", quoteVo.getInsuredPersonInfo().getName(),
-                "2", "1", "1", "3", "", quoteVo.getInsuredPersonInfo().getMobile(), quoteVo.getInsuredPersonInfo().getAddr(),
+                "1", "1", "1", "3", "", quoteVo.getInsuredPersonInfo().getMobile(), quoteVo.getInsuredPersonInfo().getAddr(),
                 quoteVo.getInsuredPersonInfo().getPostCode(), quoteVo.getInsuredPersonInfo().getPostAddress(), quoteVo.getInsuredPersonInfo().getOrganizationCode(),
                 quoteVo.getInsuredPersonInfo().getAge(), birthDate, "", "01", "008zg", quoteVo.getInsuredPersonInfo().getEmail(), "", "汉", null, quoteVo.getInsuredPersonInfo().getAddr(), null, null, "1", "", "",
                 "0", "", "", "", "1", "1", "0", "", "", "", ""));
         // 车主
-        insuredList.add(createInsured3("3", "", quoteVo.getOwnersInfo().getIdentifyNumber(), "01", quoteVo.getOwnersInfo().getName(), "2", "1", "1", "3", "",
+        insuredList.add(createInsured3("3", "", quoteVo.getOwnersInfo().getIdentifyNumber(), "01", quoteVo.getOwnersInfo().getName(), "3", "1", "1", "1", "",
                 quoteVo.getOwnersInfo().getMobile(), quoteVo.getOwnersInfo().getAddr(), quoteVo.getOwnersInfo().getPostCode(), quoteVo.getOwnersInfo().getPostAddress(), quoteVo.getOwnersInfo().getOrganizationCode(),
                 quoteVo.getOwnersInfo().getAge(), birthDate, "", "", "",
                 "", "", "", "", "", "", "", "", "", "", ""));
@@ -546,7 +561,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         insured.setEmail(email);
         insured.setBusinessLicenseType(businessLicenseType);
         insured.setNation(nation);
-        insured.setIdentifyIssuer(null);
+        insured.setIdentifyIssuer(identifyIssuer);
         //证件地址
         insured.setIdentifyAddress(identifyAddress);
         insured.setIdentifyStartDate(identifyStartDate);
@@ -599,7 +614,6 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
      * @param carInsuredRelation
      * @param businessSort
      * @param linkerName
-     * @param isSpecialDInsured
      * @param specialDInsuredName
      * @param specialDInsuredIDType
      * @param specialDInsuredID
@@ -760,7 +774,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         insured.setIsIndividualBusi("");
         insured.setEmail(email);
         insured.setBusinessLicenseType(businessLicenseType);
-
+        insured.setIdentifyIssuer(null);
         insured.setNation(nation);
         //证件地址
         insured.setIdentifyAddress(identifyAddress);
@@ -1003,36 +1017,78 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
     private List<BoHaiCrawlerQuotationRequest2.ItemKind> buildSyItemKindList(QuoteVo quoteVo) {
         List<BoHaiCrawlerQuotationRequest2.ItemKind> itemKinds = new java.util.ArrayList<>();
 
+        // 构建商业险险种
         List<KindInfoVo> kindInfoVo = quoteVo.getKindInfoVo();
-        for (int i = 0; i < kindInfoVo.size(); i++) {
-            BoHaiCrawlerQuotationRequest2.ItemKind item = new BoHaiCrawlerQuotationRequest2.ItemKind();
-            item.setItemKindNo((i + 1) + "");
-            item.setKindCode(kindInfoVo.get(i).getKindCode());
-            item.setKindName(kindInfoVo.get(i).getKindName());
-            item.setOperateType("");
-            item.setStartDate(kindInfoVo.get(i).getStartDate());
-            item.setStartHour("0");
-            item.setEndDate(kindInfoVo.get(i).getEndDate());
-            item.setEndHour("24");
-            item.setAmount(kindInfoVo.get(i).getAmount());
-            item.setUnitAmount("");
-            item.setQuantity("");
-            item.setModeCode("");
-            item.setModeName("");
-            item.setShortRateFlag("3");
-            item.setShortRate("");
-            item.setCalculateFlag("Y");
-            item.setRate("");
-            item.setNotDeductibleFlag("0");
-            item.setDeductibleRatio("");
-            item.setDiscount("");
-            item.setAdjustRate("");
-            item.setValue("");
-            itemKinds.add(item);
+        if (kindInfoVo != null) {
+            for (int i = 0; i < kindInfoVo.size(); i++) {
+                BoHaiCrawlerQuotationRequest2.ItemKind item = buildBaseItemKind(i + 1);
+                KindInfoVo kind = kindInfoVo.get(i);
+                item.setKindCode(kind.getKindCode());
+                item.setKindName(kind.getKindName());
+                item.setStartDate(kind.getStartDate());
+                item.setEndDate(kind.getEndDate());
+                item.setAmount(kind.getAmount());
+                itemKinds.add(item);
+            }
         }
+
+        // 构建驾意险
+        buildJyItemKindLIst(quoteVo, itemKinds);
+
         return itemKinds;
     }
 
+    /**
+     * 构建交驾意险险种列表
+     * @param quoteVo
+     * @param itemKinds
+     */
+    private void buildJyItemKindLIst(QuoteVo quoteVo, List<BoHaiCrawlerQuotationRequest2.ItemKind> itemKinds) {
+        List<AccidentalDrivingVo> accidentalDrivings = quoteVo.getAccidentalDrivings();
+        if (!CollectionUtils.isEmpty(accidentalDrivings)) {
+            int startIndex = itemKinds.size() + 1;
+            for (int i = 0; i < accidentalDrivings.size(); i++) {
+                BoHaiCrawlerQuotationRequest2.ItemKind item = buildBaseItemKind(startIndex + i);
+                AccidentalDrivingVo driving = accidentalDrivings.get(i);
+                item.setKindCode("O");
+                item.setKindName(driving.getProductName());
+                item.setStartDate(DateTimeUtil.parseLocalDateToString(quoteVo.getCiRiskInfoVo().getStartDate(), DateTimeUtil.DATE_PATTERN));
+                item.setEndDate(DateTimeUtil.parseLocalDateToString(quoteVo.getCiRiskInfoVo().getEndDate(), DateTimeUtil.DATE_PATTERN));
+                item.setAmount(driving.getSumAmount());
+                item.setUnitAmount("10000.00");
+                item.setQuantity(String.valueOf(driving.getQuantity()));
+                itemKinds.add(item);
+            }
+        }
+    }
+
+    /**
+     * 构建 商业险险种 and 驾意险险种 通用字段设置
+     *
+     * @param itemKindNo 险种序号
+     * @return BoHaiCrawlerQuotationRequest2.ItemKind
+     */
+    private BoHaiCrawlerQuotationRequest2.ItemKind buildBaseItemKind(int itemKindNo) {
+        BoHaiCrawlerQuotationRequest2.ItemKind item = new BoHaiCrawlerQuotationRequest2.ItemKind();
+        item.setItemKindNo(String.valueOf(itemKindNo));
+        item.setOperateType("");
+        item.setStartHour("0");
+        item.setEndHour("24");
+        item.setUnitAmount("");
+        item.setModeCode("");
+        item.setModeName("");
+        item.setShortRateFlag("3");
+        item.setShortRate("");
+        item.setCalculateFlag("Y");
+        item.setRate("");
+        item.setNotDeductibleFlag("0");
+        item.setDeductibleRatio("");
+        item.setDiscount("");
+        item.setAdjustRate("");
+        item.setValue("");
+        return item;
+    }
+
     /**
      * 构建商业险主信息  50个字段
      *
@@ -1045,17 +1101,17 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         // 农业标志:012001=非农业
         mainInfo.setAgriflag("012001");
         mainInfo.setClassCode("");
-        // 险种代码:0380=商业险
-        mainInfo.setRiskCode("0380");
+        // 险种代码:0380=商业险 0382=交强险+驾意险
+        mainInfo.setRiskCode("0382");
         mainInfo.setContractNo("");
         mainInfo.setDiscount("");
         mainInfo.setCurrency("CNY");
         mainInfo.setLastPolicyNo("");
         // 续保标志:0=非续保,1=续保
         mainInfo.setRenewalFlag("0");
-        mainInfo.setStartDate(quoteVo.getBiRiskInfoVo().getStartDate());
+        mainInfo.setStartDate(quoteVo.getBiRiskInfoVo() != null ? DateTimeUtil.parseLocalDateToString(quoteVo.getBiRiskInfoVo().getStartDate(), DateTimeUtil.DATE_PATTERN) : DateTimeUtil.parseLocalDateToString(quoteVo.getCiRiskInfoVo().getStartDate(), DateTimeUtil.DATE_PATTERN));
         mainInfo.setStartHour("0");
-        mainInfo.setEndDate(quoteVo.getBiRiskInfoVo().getEndDate());
+        mainInfo.setEndDate(quoteVo.getBiRiskInfoVo() != null ? DateTimeUtil.parseLocalDateToString(quoteVo.getBiRiskInfoVo().getEndDate(), DateTimeUtil.DATE_PATTERN) : DateTimeUtil.parseLocalDateToString(quoteVo.getCiRiskInfoVo().getEndDate(), DateTimeUtil.DATE_PATTERN));
         mainInfo.setEndHour("24");
         mainInfo.setImmediatelyActiveFlag("");
         // 生效开始时间
@@ -1067,7 +1123,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         mainInfo.setSpecialContractSummary("");
         mainInfo.setNoneFluctuateFlag("");
         // 无赔款优待系数(NCD):1=无优惠
-        mainInfo.setNcdCoefficient("1");
+        mainInfo.setNcdCoefficient("");
         mainInfo.setChannelCoefficient("1.00");
         mainInfo.setUnderwritingCoefficient("");
         mainInfo.setAdjustCoefficient("");
@@ -1079,7 +1135,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         mainInfo.setProposalNo("");
         // 客户属性:001=普通客户
         mainInfo.setCustomerProperty("001");
-        mainInfo.setRiskCoefficient("362001");
+        mainInfo.setRiskCoefficient("362001");// 渤海是362000
         mainInfo.setBusinessCoefficient("363000");
         mainInfo.setVehicleCoefficient("000");
         mainInfo.setCustomerCoefficient("364001");
@@ -1098,7 +1154,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         mainInfo.setPriceId("");
         mainInfo.setNoTaxAmount("");
         mainInfo.setTaxAmount("");
-        mainInfo.setPricingAdjustValue("");
+        mainInfo.setPricingAdjustValue("1");
         mainInfo.setExpPricingAdjustValue("");
         mainInfo.setNoneFluctuateFeeRate("");
         return mainInfo;
@@ -1107,13 +1163,19 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
     /**
      * 处理报价响应
      *
-     * @param quoteVo                        报价Vo
-     * @param boHaiCrawlerQuotationResponse2 报价响应
+     * @param quoteVo 报价Vo
+     * @param response 报价响应
      * @return QuoteResultsVo
      */
     private QuoteResultsVo handleQuotationResponse(QuoteVo quoteVo, BoHaiCrawlerQuotationResponse2 response) {
         if (ResponseCode.Quotation_Failed.getCode().equals(response.getHead().getReturnCode())) {
             log.info("报价失败");
+            // 检查是否为重复投保
+            String returnMessage = response.getHead().getReturnMessage();
+            if (returnMessage != null && returnMessage.contains("发生重复投保")) {
+                log.info("检测到重复投保,尝试重新报价");
+                return handleRepeatInsurance(quoteVo, response, returnMessage);
+            }
             // 报价失败
             boHaiCrawlerOrderService.save(quoteVo, response, false);
             return BoHaiCrawlerQuoteResultsVoBuild.buildQuoteFailResultsVo(response);
@@ -1124,6 +1186,106 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         return BoHaiCrawlerQuoteResultsVoBuild.buildQuoteResultsVo(quoteVo.getOrder().getOrdersNo(), quoteVo, response);
     }
 
+    /**
+     * 处理重复投保情况
+     *
+     * @param quoteVo 报价Vo
+     * @param response 报价响应
+     * @param returnMessage 返回消息
+     * @return QuoteResultsVo
+     */
+    private QuoteResultsVo handleRepeatInsurance(QuoteVo quoteVo, BoHaiCrawlerQuotationResponse2 response, String returnMessage) {
+        try {
+            log.info("开始处理重复投保情况");
+            
+            // 从错误消息中提取终保日期
+            String endDateStr = extractEndDateFromErrorMessage(returnMessage);
+            if (endDateStr == null || endDateStr.isEmpty()) {
+                log.warn("无法从错误消息中提取终保日期,直接返回失败结果");
+                boHaiCrawlerOrderService.save(quoteVo, response, false);
+                return BoHaiCrawlerQuoteResultsVoBuild.buildQuoteFailResultsVo(response);
+            }
+            
+            log.info("提取到的终保日期: {}", endDateStr);
+            
+            // 计算新的保险期间:从原终保日期开始,到一年后结束
+            String newStartDate = endDateStr + ":00"; // 添加秒部分
+            String newEndDate = DateUtil.getNextYearDateStr(newStartDate);
+            
+            log.info("新的保险期间 - 开始日期: {}, 结束日期: {}", newStartDate, newEndDate);
+            
+            // 更新报价请求中的保险期间
+            updateInsurancePeriod(quoteVo, newStartDate, newEndDate);
+            
+            // 重新执行报价流程
+            return executeQuotation(quoteVo);
+            
+        } catch (Exception e) {
+            log.error("处理重复投保异常", e);
+            // 如果处理重复投保过程中出现异常,返回原始失败结果
+            boHaiCrawlerOrderService.save(quoteVo, response, false);
+            return BoHaiCrawlerQuoteResultsVoBuild.buildQuoteFailResultsVo(response);
+        }
+    }
+
+    /**
+     * 从错误消息中提取终保日期
+     *
+     * @param errorMessage 错误消息
+     * @return 终保日期字符串
+     */
+    private String extractEndDateFromErrorMessage(String errorMessage) {
+        try {
+            // 使用StringSubStringUtils工具类提取终保日期
+            String endDate = StringSubStringUtils.subjectStringContentByTrafficPolicyDTOBenginDate(errorMessage, ":", "终保日期");
+            if (endDate != null && !endDate.isEmpty()) {
+                // 清理日期格式,移除可能的空格
+                return endDate.trim();
+            }
+            
+            // 如果上面的方法没有提取到,尝试另一种格式
+            endDate = StringSubStringUtils.subjectStringContentByBusinessPolicyEndDate(errorMessage, "终保日期:");
+            if (endDate != null && !endDate.isEmpty()) {
+                return endDate.trim();
+            }
+            
+            log.warn("无法从错误消息中提取终保日期: {}", errorMessage);
+            return null;
+        } catch (Exception e) {
+            log.error("提取终保日期异常", e);
+            return null;
+        }
+    }
+
+    /**
+     * 更新报价请求中的保险期间
+     *
+     * @param quoteVo 报价Vo
+     * @param startDate 开始日期
+     * @param endDate 结束日期
+     */
+    private void updateInsurancePeriod(QuoteVo quoteVo, String startDate, String endDate) {
+        try {
+            // 更新交强险的保险期间
+            if (quoteVo.getCiRiskInfoVo() != null) {
+                quoteVo.getCiRiskInfoVo().setStartDate(startDate.substring(0, 10)); // 只取日期部分
+                quoteVo.getCiRiskInfoVo().setEndDate(endDate.substring(0, 10));
+                log.info("已更新交强险保险期间 - 开始日期: {}, 结束日期: {}", 
+                    quoteVo.getCiRiskInfoVo().getStartDate(), quoteVo.getCiRiskInfoVo().getEndDate());
+            }
+            
+            // 更新商业险的保险期间
+            if (quoteVo.getBiRiskInfoVo() != null) {
+                quoteVo.getBiRiskInfoVo().setStartDate(startDate.substring(0, 10));
+                quoteVo.getBiRiskInfoVo().setEndDate(endDate.substring(0, 10));
+                log.info("已更新商业险保险期间 - 开始日期: {}, 结束日期: {}", 
+                    quoteVo.getBiRiskInfoVo().getStartDate(), quoteVo.getBiRiskInfoVo().getEndDate());
+            }
+        } catch (Exception e) {
+            log.error("更新保险期间异常", e);
+        }
+    }
+
     /**
      * 核保
      *
@@ -1508,18 +1670,18 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         bodyDTO.setBasicRateCode("");
         // 登录机构编码,先写死
         bodyDTO.setComCode("14070201");
-        bodyDTO.setEffectiveDate(quoteVo.getCiRiskInfoVo().getStartDate());
-        bodyDTO.setExpireDate(quoteVo.getCiRiskInfoVo().getEndDate());
+        bodyDTO.setEffectiveDate(DateTimeUtil.parseLocalDateToString(quoteVo.getCiRiskInfoVo().getStartDate(), DateTimeUtil.DATE_PATTERN));
+        bodyDTO.setExpireDate(DateTimeUtil.parseLocalDateToString(quoteVo.getCiRiskInfoVo().getEndDate(), DateTimeUtil.DATE_PATTERN));
         bodyDTO.setEndHour("24");
         bodyDTO.setStartHour("0");
-        bodyDTO.setRiskCode(quoteVo.getProductId());
-        bodyDTO.setBusinessNature(quoteVo.getCarInfoVo().getCarNatureCode());
-        bodyDTO.setEngineNo(boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getEngineNumber());
-        bodyDTO.setVin(boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getVinCode());
+        bodyDTO.setRiskCode(quoteVo.getOrder().getProductId());// 0380-交强险
+        bodyDTO.setBusinessNature("0");// 传0可以,赋值传参报错,不清楚含义
+        bodyDTO.setEngineNo(ObjectUtils.isEmpty(boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getEngineNumber()) ? quoteVo.getCarInfoVo().getEngineNo() : boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getEngineNumber());
+        bodyDTO.setVin(boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getVinCodeRe());
         bodyDTO.setLicensePlateNo(boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getPlateNumber());
         //车牌类型
         bodyDTO.setLicensePlateType(quoteVo.getCarInfoVo().getLicenseKindCode());
-        bodyDTO.setFirstRegisterDate(boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getRegisterDate());
+        bodyDTO.setFirstRegisterDate(ObjectUtils.isEmpty(boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getRegisterDate()) ? quoteVo.getCarInfoVo().getRegisterDate() : boHaiCrawlerCarApiResponse.getData().getJyCarModelFill().getRegisterDate());
         bodyDTO.setModelCode(boHaiCrawlerCarApiResponse.getData().getPrpDCarModels().get(0).getIndustryCarTypeCode());
         //平台车型代码
         bodyDTO.setPlatFormModelCode(boHaiCrawlerCarApiResponse.getData().getPrpDCarModels().get(0).getIndustryCarTypeCode());
@@ -1532,8 +1694,8 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
 
         //车辆动力参数
         //排量
-        bodyDTO.setExhaustScale(Double.parseDouble(quoteVo.getCarInfoVo().getDisplacement()));
-        bodyDTO.setDisplacement("");
+        bodyDTO.setExhaustScale(ObjectUtils.isEmpty(quoteVo.getCarInfoVo().getDisplacement()) ? 0.0 : Double.parseDouble(quoteVo.getCarInfoVo().getDisplacement()));
+        bodyDTO.setDisplacement(ObjectUtils.isEmpty(quoteVo.getCarInfoVo().getDisplacement()) ? 0.0 : Double.parseDouble(quoteVo.getCarInfoVo().getDisplacement()));
         bodyDTO.setPower(quoteVo.getCarInfoVo().getPowerScale());
         bodyDTO.setModelEnergyType(quoteVo.getCarInfoVo().getEnergyTypeCode());
         bodyDTO.setPureRange("");
@@ -1550,7 +1712,7 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         bodyDTO.setRatedPassengerCapacity(quoteVo.getCarInfoVo().getSeatCount());
         bodyDTO.setLimitLoadPerson(quoteVo.getCarInfoVo().getSeatCount());
         bodyDTO.setTonnage("0.0000");
-        bodyDTO.setLimitLoad(quoteVo.getCarInfoVo().getLimitLoad());
+        bodyDTO.setLimitLoad("0".equals(quoteVo.getCarInfoVo().getLimitLoad()) ? "0.0000" : quoteVo.getCarInfoVo().getLimitLoad());
         bodyDTO.setWholeWeight(quoteVo.getCarInfoVo().getCompleteKerbMass());
 
         //价格与价值信息
@@ -1570,6 +1732,11 @@ public class BoHaiCrawlerRequestImpl implements BoHaiCrawlerRequest {
         bodyDTO.setCarOwnerIdentifyType("01");
         bodyDTO.setSalesChannelRefCode("");
         bodyDTO.setPrecisePriceComCode(true);
+        bodyDTO.setOwnerName("");
+        bodyDTO.setOwnerCertificateType("01");
+        bodyDTO.setOwnerCertificateNum("");
+        bodyDTO.setCertificateType("");
+        bodyDTO.setCertificateNo("");
         boHaiCrawlerVehicleConfirmationReqeust1.setBody(bodyDTO);
         log.info("[车辆确认]请求参数的值:{}", JSON.toJSONString(boHaiCrawlerVehicleConfirmationReqeust1));
         //调用车辆确认接口

+ 2 - 2
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/PythonExecutor.java

@@ -307,8 +307,8 @@ public class PythonExecutor {
         }*/
         // 获取token的值
         String token = PythonExecutor.executeAndGetToken(
-                "e:/project/jzg/tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/novel.py",
-                "E:\\project\\memorize_backend\\venv\\Scripts\\python.exe", 120);
+                "E:/IdeaProjects/jzg/tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/novel.py",
+                "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/python.exe", 120);
         if (token != null) {
             System.out.println("获取到的token: " + token);
         } else {

+ 3 - 3
tenant/insurance/quotation-bohai/src/main/java/com/jzg/quotation/bohai/crawler/util/novel.py

@@ -116,9 +116,10 @@ class BHBX_login():
 # 账号:114050281   密码:Bhcx1234  openId  odviKt0g-CP5NVNnZKiHEStPbRoU
 
 usernamelist = [
-    {"username":"114050281","passward":"Bhcx1234","openId":"odviKt0g-CP5NVNnZKiHEStPbRoU"} # odviKt0g-CP5NVNnZKiHEStPbRoU
+    {"username":"114050281","passward":"Bhcx1234","openId":"odviKt0g-CP5NVNnZKiHEStPbRoU"}, # odviKt0g-CP5NVNnZKiHEStPbRoU
+    {"username":"114050287","passward":"Bhcx1234","openId":"odviKt0g-CP5NVNnZKiHEStPbRIU"}, # odviKt0g-CP5NVNnZKiHEStPbRoU
 ]
-username = "114050281"
+username = "114050287"
 password = ""
 openId = ""
 for item in usernamelist:
@@ -132,4 +133,3 @@ if openId == "":
 bhbx = BHBX_login(username,password,openId)
 print(bhbx.login())
 
-

+ 10 - 2
tenant/insurance/quotation-commons/src/main/java/com/jzg/quotation/commons/utils/DateTimeUtil.java

@@ -136,8 +136,16 @@ public class DateTimeUtil {
      * @return String 日期
      */
     public static String parseLocalDateToString(String localDateStr, String pattern) {
-        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
-        return LocalDate.parse(localDateStr, dateTimeFormatter).toString();
+        // 判断是否包含时间部分
+        if (localDateStr.contains(" ") || localDateStr.contains(":")) {
+            // 包含时间部分,先解析为LocalDateTime,再提取日期
+            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN);
+            return LocalDateTime.parse(localDateStr, dateTimeFormatter).toLocalDate().toString();
+        } else {
+            // 仅日期部分,直接解析为LocalDate
+            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
+            return LocalDate.parse(localDateStr, dateTimeFormatter).toString();
+        }
     }