Kaynağa Gözat

fix: 添加投保后查询功能

luofeiyun 2 hafta önce
ebeveyn
işleme
2c7ab3b1c9

+ 1 - 1
ship-module-trade/ship-module-trade-api/src/main/java/com/yc/ship/module/trade/api/insurance/dto/InsuredCancelDTO.java

@@ -17,5 +17,5 @@ public class InsuredCancelDTO {
     /**
      *  //必填 - 保单号
      */
-   private String policyNum;
+   private String policyNo;
 }

+ 4 - 0
ship-module-trade/ship-module-trade-api/src/main/java/com/yc/ship/module/trade/enums/TradeMqConstants.java

@@ -41,4 +41,8 @@ public class TradeMqConstants {
 
     public static final String DL_OTA_PRODUCT_PRICE_STOCK ="dl.ota.product.price.stock";
     public static final String DELAY_OTA_PRODUCT_PRICE_STOCK ="delay.ota.product.price.stock";
+
+    public static final String DL_EXCHANGE_INSURANCE ="dl_exchange_insurance";
+
+    public static final String DL_INSURANCE_QUERY ="dl.trade.insurance.query";
 }

+ 32 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/framework/mq/TradeMqConfig.java

@@ -8,6 +8,9 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import static com.yc.ship.module.trade.enums.TradeMqConstants.*;
 
 
@@ -45,6 +48,11 @@ public class TradeMqConfig {
     public static final String DL_QUEUE_OTA_NOTIFY ="dl_queue_ota_notify";
     public static final String DELAY_QUEUE_OTA_PRICE_STOCK ="delay_queue_ota_price_stock";
 
+    /**
+     * 保险延迟反查
+     */
+    public static final String DL_QUEUE_INSURANCE_QUERY ="dl_queue_insurance_query";
+
 
     @Bean
     public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) {
@@ -310,4 +318,28 @@ public class TradeMqConfig {
     Binding bindOtaProductPriceStockQueue(@Qualifier("otaProductPriceStockQueue") Queue queue, @Qualifier("tradeOrderExchange") TopicExchange exchange) {
         return BindingBuilder.bind(queue).to(exchange).with(DELAY_OTA_PRODUCT_PRICE_STOCK);
     }
+
+    /**
+     * 保险交换机
+     * @return
+     */
+    @Bean(name = "insuranceQueryExchange")
+    public CustomExchange insuranceQueryExchange(){
+        Map<String, Object> args = new HashMap<>();
+        args.put("x-delayed-type", "direct");
+        return new CustomExchange(DL_EXCHANGE_INSURANCE, "x-delayed-message", true, false, args);
+    }
+    /**
+     * 保险反查队列
+     * @return
+     */
+    @Bean(name = "insuranceQueryQueue")
+    public Queue insuranceQueryQueue(){
+        return new Queue(DL_QUEUE_INSURANCE_QUERY, true);
+    }
+
+    @Bean
+    Binding bindInsuranceQueryQueue(@Qualifier("insuranceQueryQueue") Queue queue, @Qualifier("insuranceQueryExchange") CustomExchange exchange) {
+        return BindingBuilder.bind(queue).to(exchange).with(DL_QUEUE_INSURANCE_QUERY).noargs();
+    }
 }

+ 63 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/framework/mq/TradeMqReceiver.java

@@ -2,15 +2,21 @@ package com.yc.ship.module.trade.framework.mq;
 
 
 import cn.hutool.core.map.MapUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.rabbitmq.client.Channel;
+import com.yc.ship.framework.common.pojo.CommonResult;
 import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
 import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderDO;
+import com.yc.ship.module.trade.dal.mysql.insurance.InsuranceMapper;
+import com.yc.ship.module.trade.service.insurance.InsuranceService;
 import com.yc.ship.module.trade.service.order.TradeOrderBizService;
 import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
 import com.yc.ship.module.trade.service.order.handler.TradeOrderHandler;
 import com.yc.ship.module.trade.service.ota.OtaStandardService;
 import com.yc.ship.module.trade.service.pay.TradeOrderPayService;
 import com.yc.ship.module.trade.service.refund.TradeRefundService;
+import com.yc.ship.module.trade.utils.InsuranceUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.amqp.core.Message;
 import org.springframework.amqp.rabbit.annotation.RabbitListener;
@@ -18,6 +24,7 @@ import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
 
@@ -48,6 +55,15 @@ public class TradeMqReceiver {
     @Resource
     private OtaStandardService otaStandardService;
 
+    @Resource
+    private InsuranceUtil insuranceUtil;
+
+    @Resource
+    private TradePublishUtils tradePublishUtils;
+
+    @Resource
+    private InsuranceService insuranceService;
+
 
     /**
      * 处理订单创建成功消息
@@ -352,4 +368,51 @@ public class TradeMqReceiver {
             channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
         }
     }
+
+    @RabbitListener(queues = TradeMqConfig.DL_QUEUE_INSURANCE_QUERY, concurrency = "2")
+    @TenantIgnore
+    public void processInsuranceQuery(String data) {
+        log.info("收到保险查询结果消息 :" + data);
+
+        try {
+            CommonResult commonResult = insuranceUtil.queryInsurance(data);
+            if (!commonResult.isSuccess()) {
+                log.error("保险查询结果消息通知出现错误{}", commonResult.getMsg());
+                tradePublishUtils.publishInsuranceQueryMsg(data, 1000*60);
+                return;
+            } else {
+                String checkedData = (String) commonResult.getCheckedData();
+                JSONObject jsonObject = JSONObject.parseObject(checkedData);
+                BigDecimal paiedAmount = jsonObject.getBigDecimal("paiedAmount");
+                JSONArray policies = jsonObject.getJSONArray("policies");
+                if(policies == null) {
+                    return;
+                }
+                JSONObject policy = policies.getJSONObject(0);
+                if(policy == null) {
+                    return;
+                }
+                String status = policy.getString("status");
+                if("PROCESSING".equals(status)) {
+                    log.error("保险查询结果,投保中,继续查询");
+                    tradePublishUtils.publishInsuranceQueryMsg(data, 1000 * 60);
+                    return;
+                } else if("FAIL".equals(status)) {
+                    log.error("保险查询结果,投保失败,不再查询");
+                    return;
+                } else if("SUCCESS".equals(status)) {
+                    log.error("保险查询结果,投保成功,不再查询");
+                    Long externalPolicyNumber = policy.getLong("externalPolicyNumber");
+                    String policyNo = policy.getString("policyNo");
+                    insuranceService.handleInsuranceQuery(paiedAmount, policyNo, externalPolicyNumber, status);
+                    return;
+                }
+
+            }
+
+        } catch (Exception e) {
+            log.error("保险查询结果消息MQ通知出现错误{}", e.getMessage());
+        }
+
+    }
 }

+ 17 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/framework/mq/TradePublishUtils.java

@@ -1,5 +1,7 @@
 package com.yc.ship.module.trade.framework.mq;
 
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.amqp.rabbit.connection.CorrelationData;
 import org.springframework.amqp.rabbit.core.RabbitTemplate;
 import org.springframework.retry.annotation.Backoff;
@@ -9,6 +11,7 @@ import org.springframework.stereotype.Component;
 import javax.annotation.Resource;
 
 import static com.yc.ship.module.trade.enums.TradeMqConstants.*;
+import static com.yc.ship.module.trade.framework.mq.TradeMqConfig.DL_QUEUE_INSURANCE_QUERY;
 
 
 /**
@@ -16,6 +19,7 @@ import static com.yc.ship.module.trade.enums.TradeMqConstants.*;
  * &#064;Author :qsl
  * &#064;Date :2025/6/21 09:18
  */
+@Slf4j
 @Component
 public class TradePublishUtils {
 
@@ -213,4 +217,17 @@ public class TradePublishUtils {
             throw new RuntimeException("发布核销检查延时消息失败");
         }
     }
+
+    /**
+     * 发送保险查询通知
+     * @param data
+     * @param delay
+     */
+    public void publishInsuranceQueryMsg(String data, long delay){
+        log.info("发送结算消息OrderId:{}, 延时毫秒:{},发送时间:{}", data, delay, DateUtil.now());
+        template.convertAndSend(DL_EXCHANGE_INSURANCE, DL_QUEUE_INSURANCE_QUERY, data, message -> {
+            message.getMessageProperties().setHeader("x-delay",delay == 0 ? 60 * 1000 : delay);
+            return message;
+        });
+    }
 }

+ 6 - 0
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/insurance/InsuranceService.java

@@ -9,6 +9,7 @@ import com.yc.ship.module.trade.controller.admin.insurance.vo.InsurancePageReqVO
 import com.yc.ship.module.trade.controller.admin.insurance.vo.InsuranceRespVO;
 import com.yc.ship.module.trade.dal.dataobject.insurance.InsuranceDO;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -63,4 +64,9 @@ public interface InsuranceService {
     void queryEpolicyAll();
 
     InsuranceDO getByOrderId(Long orderId);
+
+    /**
+     * 保险查询后处理保险数据和订单保险状态
+     */
+    void handleInsuranceQuery(BigDecimal amount, String policyNo, Long orderId, String status);
 }

+ 36 - 12
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/service/insurance/InsuranceServiceImpl.java

@@ -23,10 +23,12 @@ import com.yc.ship.module.trade.controller.admin.insurance.vo.InsuranceRespVO;
 import com.yc.ship.module.trade.controller.admin.order.vo.order.TradeOrderRespVO;
 import com.yc.ship.module.trade.controller.admin.order.vo.order.TradeVisitorRespVO;
 import com.yc.ship.module.trade.dal.dataobject.insurance.InsuranceDO;
+import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderDO;
 import com.yc.ship.module.trade.dal.mysql.insurance.InsuranceMapper;
 import com.yc.ship.module.trade.dal.mysql.order.TradeOrderMapper;
 import com.yc.ship.module.trade.dal.mysql.order.TradeVisitorMapper;
 import com.yc.ship.module.trade.enums.InsuranceStatusEnum;
+import com.yc.ship.module.trade.framework.mq.TradePublishUtils;
 import com.yc.ship.module.trade.utils.InsuranceRequestHelper;
 import com.yc.ship.module.trade.utils.InsuranceUtil;
 import lombok.extern.slf4j.Slf4j;
@@ -38,6 +40,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -82,6 +85,9 @@ public class InsuranceServiceImpl implements InsuranceService {
     @Resource
     private InsuranceUtil insuranceUtil;
 
+    @Resource
+    private TradePublishUtils tradePublishUtils;
+
     @Value("${yudao.notify.insurance}")
     private String notifyUrl;
 
@@ -174,12 +180,12 @@ public class InsuranceServiceImpl implements InsuranceService {
         insuranceApplyReqDTO.setInsureds(insuredList);
 
         //验证投保信息
-//        CommonResult commonResult = insuranceUtil.validateInsuranceRequest(insuranceApplyReqDTO);
-//        if(!commonResult.isSuccess()) {
-//            throw exception0(commonResult.getCode(),commonResult.getMsg());
-//        }
+        CommonResult commonResult = insuranceUtil.validateInsuranceRequest(insuranceApplyReqDTO);
+        if(!commonResult.isSuccess()) {
+            throw exception0(commonResult.getCode(),commonResult.getMsg());
+        }
         // 开始投保
-        CommonResult commonResult = insuranceUtil.sendInsuranceApply(insuranceApplyReqDTO);
+        commonResult = insuranceUtil.sendInsuranceApply(insuranceApplyReqDTO);
         if(!commonResult.isSuccess()) {
             throw exception0(commonResult.getCode(),commonResult.getMsg());
         }
@@ -197,6 +203,8 @@ public class InsuranceServiceImpl implements InsuranceService {
         Long id = IdWorker.getId(insuranceDO);
         insuranceDO.setId(id);
         insuranceMapper.insert(insuranceDO);
+        // 发送查询投保接口通知
+        tradePublishUtils.publishInsuranceQueryMsg(orderInfo.getOrderNo(),0);
     }
 
     /**
@@ -252,16 +260,11 @@ public class InsuranceServiceImpl implements InsuranceService {
         List<InsuredCancelDTO> insuredList = new ArrayList<>();
         InsuredCancelDTO insuredDTO = new InsuredCancelDTO();
         insuredDTO.setExternalPolicyNumber(orderInfo.getId().toString());
-        insuredDTO.setPolicyNum(insuranceDO.getPolicyNo());
+        insuredDTO.setPolicyNo(insuranceDO.getPolicyNo());
         insuredList.add(insuredDTO);
         insuranceCancelReqDTO.setInsureds(insuredList);
 
-        //验证投保信息
-//        CommonResult commonResult = insuranceUtil.validateInsuranceRequest(insuranceApplyReqDTO);
-//        if(!commonResult.isSuccess()) {
-//            throw exception0(commonResult.getCode(),commonResult.getMsg());
-//        }
-        // 开始投保
+        // 开始退保
         CommonResult commonResult = insuranceUtil.sendInsuranceCancel(insuranceCancelReqDTO);
         if(!commonResult.isSuccess()) {
             throw exception0(commonResult.getCode(),commonResult.getMsg());
@@ -286,6 +289,27 @@ public class InsuranceServiceImpl implements InsuranceService {
         return insuranceMapper.selectByOrderId(orderId);
     }
 
+    @Override
+    @Transactional
+    public void handleInsuranceQuery(BigDecimal amount, String policyNo, Long orderId, String status) {
+        InsuranceDO insuranceDO = insuranceMapper.selectByOrderId(orderId);
+        insuranceDO.setAmount(amount);
+        insuranceDO.setPolicyNo(policyNo);
+        Integer insuranceStatus = InsuranceStatusEnum.INSURE.getValue();
+        if("SUCCESS".equals(status)) {
+            insuranceStatus = InsuranceStatusEnum.SUCCESS.getValue();
+        } else if ("FAIL".equals(status)){
+            insuranceStatus = InsuranceStatusEnum.FAIL.getValue();
+        }else if ("PROCESSING".equals(status)){
+            insuranceStatus = InsuranceStatusEnum.INSURE.getValue();
+        }
+        insuranceDO.setInsuranceStatus(insuranceStatus);
+        insuranceMapper.updateById(insuranceDO);
+        TradeOrderDO tradeOrderDO = tradeOrderMapper.selectById(orderId);
+        tradeOrderDO.setIsInsure(insuranceStatus);
+        tradeOrderMapper.updateById(tradeOrderDO);
+    }
+
     /**
      * 电子保单查询
      */

+ 19 - 53
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/utils/InsuranceUtil.java

@@ -1,9 +1,12 @@
 package com.yc.ship.module.trade.utils;
 
 import com.alibaba.fastjson.JSONObject;
+import com.anji.captcha.util.MD5Util;
 import com.yc.ship.framework.common.pojo.CommonResult;
+import com.yc.ship.framework.common.util.http.HttpUtils;
 import com.yc.ship.module.trade.api.insurance.dto.InsuranceApplyReqDTO;
 import com.yc.ship.module.trade.api.insurance.dto.InsuranceCancelReqDTO;
+import com.yc.ship.module.trade.framework.mq.TradePublishUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.http.*;
 import org.springframework.stereotype.Component;
@@ -11,8 +14,10 @@ import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
 import org.springframework.web.client.RestTemplate;
 
+import javax.annotation.Resource;
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception0;
@@ -173,14 +178,8 @@ public class InsuranceUtil {
 
             log.info("阳光系统校验响应内容: {}", responseBody);
             JSONObject responseBodyJson = JSONObject.parseObject(responseBody);
-            if ("200".equals(responseBodyJson.getString("code"))) {
-                JSONObject data = responseBodyJson.getJSONObject("data");
-                String status = data.getString("status");
-                if("SUCCESS".equals(status)) {
-                    return CommonResult.success(responseBody);
-                }else {
-                    return CommonResult.error(500, "阳光系统校验返回错误: " + response.getStatusCode() + responseBody);
-                }
+            if ("SUCCESS".equals(responseBodyJson.getString("status"))) {
+                return CommonResult.success(responseBody);
             } else {
                 // 响应失败,返回错误信息
                 return CommonResult.error(500, "阳光系统校验返回错误: " + response.getStatusCode() + responseBody);
@@ -259,63 +258,30 @@ public class InsuranceUtil {
 
     public CommonResult queryInsurance(String orderNo) {
         try {
-            JSONObject request = new JSONObject();
+            Map<String, String> request = new LinkedHashMap<>();
+            request.put("appId", APPID);
             request.put("externalOrderNo", orderNo);
-            String reqJson = JSONObject.toJSONString(request);
-            String sign = SignUtil.generateMD5Sign(APPID, reqJson, KEY);
+            request.put("key", KEY);
+            String sign = MD5Util.md5(APPID+orderNo+KEY);
 
             MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
             params.add("appId", APPID);
-            params.add("req", reqJson);
+            params.add("externalOrderNo", orderNo);
             params.add("sign", sign);
 
-            HttpHeaders headers = new HttpHeaders();
-            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
 
-            HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, headers);
+            String url = HOST + QUERY_URL + "?appId=" + APPID + "&externalOrderNo=" + orderNo + "&sign=" + sign;
 
-            log.info("发送退保请求到阳光系统: {}", HOST + RECEIVE_URL);
-            log.info("请求参数: appId={}, req={}, sign={}", APPID, reqJson, sign);
 
-            // 发送请求并获取响应
-            ResponseEntity<byte[]> response = restTemplate.exchange(
-                    HOST + RECEIVE_URL,
-                    HttpMethod.POST,
-                    entity,
-                    byte[].class
-            );
+            log.info("发送查询请求到阳光系统: {}", url);
 
-            log.info("阳光系统响应状态码: {}", response.getStatusCode());
-
-            // 手动处理响应字节流,确保使用UTF-8编码
-            byte[] responseBytes = response.getBody();
-            String responseBody = null;
-            if (responseBytes != null) {
-                try {
-                    responseBody = new String(responseBytes, "UTF-8");
-                } catch (UnsupportedEncodingException e) {
-                    log.error("解析响应内容编码失败", e);
-                    responseBody = new String(responseBytes);
-                }
-            }
-
-            log.info("阳光系统响应内容: {}", responseBody);
-            JSONObject responseBodyJson = JSONObject.parseObject(responseBody);
-
-            if (response.getStatusCode() == HttpStatus.OK) {
-                String status = responseBodyJson.getString("status");
-                if("FAIL".equals(status)) {
-                    return CommonResult.error(500, "阳光系统退保返回错误: " + response.getStatusCode() + responseBody);
-                }else {
-                    return CommonResult.success(responseBody);
-                }
-            } else {
-                return CommonResult.error(500, "阳光系统退保返回错误: " + response.getStatusCode() + responseBody);
-            }
+            String s = HttpUtils.get(url, null);
 
+            log.info("阳光系统查询响应内容: {}", s);
+            return CommonResult.success(s);
         } catch (Exception e) {
-            log.error("发送退保请求失败", e);
-            return CommonResult.error(500,"发送退保请求失败: " + e.getMessage());
+            log.error("发送查询请求失败", e);
+            return CommonResult.error(500,"发送查询请求失败: " + e.getMessage());
         }
     }
 }

+ 1 - 1
ship-module-trade/ship-module-trade-biz/src/main/java/com/yc/ship/module/trade/utils/SignUtil.java

@@ -113,7 +113,7 @@ public class SignUtil {
         String HOST = "https://lbb-admin.anyitech.ltd";
         String QUERY_URL = "/policy/querystatus.do"; // 保单状态查询接口
         RestTemplate restTemplate = new RestTemplate();
-        String orderNo = "lfy001-20260521-YC-1";
+        String orderNo = "tys-20260716-YC-39";
         String APPID = "123456";   // appId
         String KEY = "goldpalm"; // key
         Map<String, String> request = new LinkedHashMap<>();

+ 4 - 5
ship-server-web/src/main/resources/application-sxtest.yaml

@@ -112,11 +112,10 @@ xxl:
 spring:
   # RabbitMQ 配置项,对应 RabbitProperties 配置类
   rabbitmq:
-    host: 127.0.0.1 # RabbitMQ 服务的地址
-    port: 5672 # RabbitMQ 服务的端口
-    username: ticket # RabbitMQ 服务的账号
-    password: ticket # RabbitMQ 服务的密码
-    virtual-host: /ticket # RabbitMQ 服务的密码
+    host: 10.3.10.50 # RabbitMQ 服务的地址
+    port: 55672 # RabbitMQ 服务的端口
+    username: rabbitmq # RabbitMQ 服务的账号
+    password: rabbitmq # RabbitMQ 服务的密码
   # Kafka 配置项,对应 KafkaProperties 配置类
   kafka:
     bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔