Преглед на файлове

Merge remote-tracking branch 'origin/master'

lixiaolong преди 2 месеца
родител
ревизия
cabcafcd0a
променени са 20 файла, в които са добавени 543 реда и са изтрити 59 реда
  1. 4 0
      commons/src/main/java/com/jzg/commons/entity/finance/dto/CompanySuperviseSettlementReportDto.java
  2. 62 0
      commons/src/main/java/com/jzg/commons/entity/finance/dto/InsFeeFollowOrderReconciliationSaveDTO.java
  3. 96 0
      commons/src/main/java/com/jzg/commons/entity/finance/po/InsFeeFollowOrderReconciliation.java
  4. 41 0
      commons/src/main/java/com/jzg/commons/entity/finance/vo/InsFeeFollowOrderReconciliationVO.java
  5. 3 0
      commons/src/main/java/com/jzg/commons/entity/orders/vo/OrderListVo.java
  6. 1 0
      gateway/src/main/resources/application-dev.yml
  7. 1 0
      gateway/src/main/resources/application-prod.yml
  8. 1 0
      gateway/src/main/resources/application-test.yml
  9. 14 6
      tenant/insurance/quotation-hengbang/src/main/java/com/jzg/quotation/hengbang/crawler/component/HengBangCrawlerRequestComponent.java
  10. 90 32
      tenant/insurance/quotation-hengbang/src/main/java/com/jzg/quotation/hengbang/crawler/service/Impl/HengBangCrawlerRequestImpl.java
  11. 1 1
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeOrdersServiceImpl.java
  12. 5 0
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/state/config/OrderStateConfig.java
  13. 1 0
      tenant/insurance/quotation-summary/src/main/resources/mapper/InsOrdersMapper.xml
  14. 60 0
      tenant/organization/src/main/java/com/jzg/organization/controller/InsFeeFollowOrderReconciliationController.java
  15. 13 0
      tenant/organization/src/main/java/com/jzg/organization/mapper/InsFeeFollowOrderReconciliationMapper.java
  16. 5 0
      tenant/organization/src/main/java/com/jzg/organization/mapper/InsPlyIncomeInvoiceSettlementMapper.java
  17. 28 0
      tenant/organization/src/main/java/com/jzg/organization/service/InsFeeFollowOrderReconciliationService.java
  18. 53 0
      tenant/organization/src/main/java/com/jzg/organization/service/impl/InsFeeFollowOrderReconciliationServiceImpl.java
  19. 61 18
      tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java
  20. 3 2
      tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

+ 4 - 0
commons/src/main/java/com/jzg/commons/entity/finance/dto/CompanySuperviseSettlementReportDto.java

@@ -43,6 +43,7 @@ public class CompanySuperviseSettlementReportDto implements Serializable {
     @Schema(description = "应收手续费")
     private String superviseFee;
 
+
     @Schema(description = "应收跟单费")
     private String followFee;
 
@@ -76,6 +77,9 @@ public class CompanySuperviseSettlementReportDto implements Serializable {
     @Schema(description = "虚增金额合计")
     private String totalOverinflatedAmount;
 
+    @Schema(description = "回款差额合计")
+    private String settlementPaymentDifference;
+
     @Schema(description = "子保险公司数据")
     private List<CompanySuperviseSettlementReportDto> children;
 

+ 62 - 0
commons/src/main/java/com/jzg/commons/entity/finance/dto/InsFeeFollowOrderReconciliationSaveDTO.java

@@ -0,0 +1,62 @@
+package com.jzg.commons.entity.finance.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 对账记录新增/修改参数
+ */
+@Data
+public class InsFeeFollowOrderReconciliationSaveDTO {
+
+    /**
+     * 主键ID(修改时必传,新增不传)
+     */
+    private Long id;
+
+    /**
+     * 年份
+     */
+    private Integer year;
+
+    /**
+     * 月份
+     */
+    private Integer month;
+
+    /**
+     * 保险公司ID
+     */
+    private String companyId;
+
+    /**
+     * 分支保险公司ID
+     */
+    private String partnerCompanyId;
+
+    /**
+     * 系统编码
+     */
+    private String systemCode;
+
+    /**
+     * 对账金额
+     */
+    private BigDecimal reconciliationAmount;
+
+    /**
+     * 虚增差额
+     */
+    private BigDecimal falselyIncreasedDifference;
+
+    /**
+     * 虚增原因
+     */
+    private String falselyIncreasedReason;
+
+    /**
+     * 开票类型
+     */
+    private String invoiceType;
+}

+ 96 - 0
commons/src/main/java/com/jzg/commons/entity/finance/po/InsFeeFollowOrderReconciliation.java

@@ -0,0 +1,96 @@
+package com.jzg.commons.entity.finance.po;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 手续费跟单费对账表 实体类
+ */
+@Data
+@TableName("ins_fee_follow_order_reconciliation")
+public class InsFeeFollowOrderReconciliation {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 年份
+     */
+    private Integer year;
+
+    /**
+     * 月份
+     */
+    private Integer month;
+
+    /**
+     * 保险公司ID
+     */
+    private String companyId;
+
+    /**
+     * 分支保险公司ID
+     */
+    private String partnerCompanyId;
+
+    /**
+     * 系统编码
+     */
+    private String systemCode;
+
+    /**
+     * 创建人
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 更新人
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    /**
+     * 逻辑删除标识 0-未删除 1-已删除
+     */
+    @TableLogic
+    private Integer isDelete;
+
+    /**
+     * 对账金额
+     */
+    private BigDecimal reconciliationAmount;
+
+    /**
+     * 虚增差额
+     */
+    private BigDecimal falselyIncreasedDifference;
+
+    /**
+     * 虚增原因
+     */
+    private String falselyIncreasedReason;
+
+    /**
+     * 开票类型
+     * 1、手续费 2、跟单费 3、驾意险手续费 4、驾意险跟单费 5、平台应收-车险 6、平台应收-非车险
+     */
+    private String invoiceType;
+}

+ 41 - 0
commons/src/main/java/com/jzg/commons/entity/finance/vo/InsFeeFollowOrderReconciliationVO.java

@@ -0,0 +1,41 @@
+package com.jzg.commons.entity.finance.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 对账记录返回视图对象
+ */
+@Data
+public class InsFeeFollowOrderReconciliationVO {
+
+    private Long id;
+
+    private Integer year;
+
+    private Integer month;
+
+    private String companyId;
+
+    private String partnerCompanyId;
+
+    private String systemCode;
+
+    private String createBy;
+
+    private LocalDateTime createTime;
+
+    private String updateBy;
+
+    private LocalDateTime updateTime;
+
+    private BigDecimal reconciliationAmount;
+
+    private BigDecimal falselyIncreasedDifference;
+
+    private String falselyIncreasedReason;
+
+    private String invoiceType;
+}

+ 3 - 0
commons/src/main/java/com/jzg/commons/entity/orders/vo/OrderListVo.java

@@ -157,5 +157,8 @@ public class OrderListVo {
 
     private Object mainDetails;
 
+    //错误信息
+    private String errorMessage;
+
 
 }

+ 1 - 0
gateway/src/main/resources/application-dev.yml

@@ -104,6 +104,7 @@ spring:
                   - /newCarJudgeRules/**
                   - /sysDistributionSetting/**
                   - /organization/**
+                  - /followReconciliation/**
 
         - id: summary_route
           uri: http://localhost:9898/

+ 1 - 0
gateway/src/main/resources/application-prod.yml

@@ -96,6 +96,7 @@ spring:
                   - /sysDistributionSetting/**
                   - /organization/wechat/**
                   - /signIn/**
+                  - /followReconciliation/**
 
         - id: summary_route
           uri: http://172.24.144.227:9898/

+ 1 - 0
gateway/src/main/resources/application-test.yml

@@ -98,6 +98,7 @@ spring:
                   - /account/**
                   - /accountCard/**
                   - /amountAuditing/**
+                  - /followReconciliation/**
 
         - id: summary_route
           uri: http://192.168.5.250:9898/

+ 14 - 6
tenant/insurance/quotation-hengbang/src/main/java/com/jzg/quotation/hengbang/crawler/component/HengBangCrawlerRequestComponent.java

@@ -334,8 +334,10 @@ public class HengBangCrawlerRequestComponent {
                         if (time != null) {
                             calculationRequest.setBegintimeCi(DateUtil.toUtcDateTime(time));
                             calculationRequest.setBegintimeBi(DateUtil.toUtcDateTime(time));
+                            return getCalculationResult(calculationRequest, headers);
+                        } else {
+                            return StrUtil.isNotBlank(detail) ? detail : responseBody;
                         }
-                        return getCalculationResult(calculationRequest, headers);
                     }
                     return StrUtil.isNotBlank(detail) ? detail : responseBody;
                 } else if (status == 400) {
@@ -363,20 +365,26 @@ public class HengBangCrawlerRequestComponent {
     }
 
 
-    // 重复投保提取时间
-    private static final Pattern DUPLICATE_END_TIME_PATTERN = Pattern.compile("终保日期 (\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2})");
+    // 重复投保提取时间(兼容两种格式:终保日期 2025-12-14 16:00 / 终保日期:2026-07-23)
+    private static final Pattern DUPLICATE_END_TIME_PATTERN = Pattern.compile("终保日期[:: ]\\s*(\\d{4}-\\d{2}-\\d{2}(?:\\s+\\d{2}:\\d{2})?)");
 
     /**
      * 提取系统自动分配的起保时间
      *
      * @param calculationResult 核心提示
-     * @return 提取到的时间字符串,未提取到返回 null
+     * @return 提取到的时间字符串(yyyy-MM-dd HH:mm:ss),未提取到返回 null
      */
     public String extractDuplicateEndTime(String calculationResult) {
         Matcher matcher = DUPLICATE_END_TIME_PATTERN.matcher(calculationResult);
         if (matcher.find()) {
-            String shortEndTime = matcher.group(1); // 提取到 2025-12-14 16:00
-            return shortEndTime + ":00"; // 补全秒数为 2025-12-14 16:00:00
+            String time = matcher.group(1);
+            if (time.length() <= 10) {
+                return time + " 00:00:00";
+            }
+            if (time.length() == 16) {
+                return time + ":00";
+            }
+            return time;
         }
         return null;
     }

+ 90 - 32
tenant/insurance/quotation-hengbang/src/main/java/com/jzg/quotation/hengbang/crawler/service/Impl/HengBangCrawlerRequestImpl.java

@@ -154,41 +154,45 @@ public class HengBangCrawlerRequestImpl implements HengBangCrawlerRequest {
         HbCrawlerCalculationRequest calculationRequest = new HbCrawlerCalculationRequest(quoteVo, plyappno, depreciationPrice);
         // 非车信息匹配核心
         matchingAccident(quoteVo, headers, plyappno, calculationRequest);
-        String resJson = hbCrawlerRequestComponent.getCalculationResult(calculationRequest, headers);
-        JSONObject resJsonObj = JSONObject.parseObject(resJson);
+
+        return executeCalculationWithRetry(calculationRequest, headers, quoteVo, plyappno);
+    }
+
+    /**
+     * 执行报价计算并处理重试逻辑(脱保、重复投保、转保车验证码)
+     */
+    private QuoteResultsVo executeCalculationWithRetry(HbCrawlerCalculationRequest calculationRequest, HttpHeaders headers, QuoteVo quoteVo, String plyappno) {
+        JSONObject resJsonObj = callCalculation(calculationRequest, headers);
         if (resJsonObj == null) {
-            return HbCrawlerQuoteResultVoBuild.build(quoteVo, null, "恒邦calculation接口返回异常");
+            return buildErrorResult(quoteVo);
         }
         String errorMsg = resJsonObj.getString("message");
-        String status = resJsonObj.getString("status");
 
         HbCrawlerProposalResponse proposalResponse = null;
         // 脱保情况 重新赋值核心建议起保时间 二次报价
         if (errorMsg.contains("脱保")) {
             calculationRequest.setOutofwarrantytype("N");
-            resJson = hbCrawlerRequestComponent.getCalculationResult(calculationRequest, headers);
-            resJsonObj = JSONObject.parseObject(resJson);
-            if (resJsonObj == null) {
-                return HbCrawlerQuoteResultVoBuild.build(quoteVo, null, "恒邦calculation接口返回异常");
+            errorMsg = retryCalculation(calculationRequest, headers);
+            if (errorMsg == null) {
+                return buildErrorResult(quoteVo);
             }
-            errorMsg = resJsonObj.getString("message");
-            status = resJsonObj.getString("status");
         }
 
-        if (errorMsg.contains("重复投保")) {
-            String time = hbCrawlerRequestComponent.extractDuplicateEndTime(errorMsg);
-            if (time != null) {
-                calculationRequest.setBegintimeCi(DateUtil.toUtcDateTime(time));
-                calculationRequest.setBegintimeBi(DateUtil.toUtcDateTime(time));
+        // 重复投保:循环重试,优先从responseBody.begintimeBi获取建议起保时间
+        int maxRetry = 3;
+        while (errorMsg.contains("重复投保") && maxRetry-- > 0) {
+            String time = getDuplicateBegintime(resJsonObj, errorMsg);
+            log.info("重复投保,重试次数:{}, 建议起保时间:{}", 3 - maxRetry, time);
+            if (time == null) {
+                break;
             }
-
-            resJson = hbCrawlerRequestComponent.getCalculationResult(calculationRequest, headers);
-            resJsonObj = JSONObject.parseObject(resJson);
+            calculationRequest.setBegintimeCi(DateUtil.toUtcDateTime(time));
+            calculationRequest.setBegintimeBi(DateUtil.toUtcDateTime(time));
+            resJsonObj = callCalculation(calculationRequest, headers);
             if (resJsonObj == null) {
-                return HbCrawlerQuoteResultVoBuild.build(quoteVo, null, "恒邦calculation接口返回异常");
+                return buildErrorResult(quoteVo);
             }
             errorMsg = resJsonObj.getString("message");
-            status = resJsonObj.getString("status");
         }
 
         if (errorMsg.contains("该车是转保车,请输入对应的转保验证码")) {
@@ -196,27 +200,23 @@ public class HengBangCrawlerRequestImpl implements HengBangCrawlerRequest {
             HbCrawlerRecordResponse recordResponse = JSONObject.parseObject(responseBody, HbCrawlerRecordResponse.class);
             // 识别验证码
             String systemJqCode = exteriorUtilsRequest.captchaIdentify(recordResponse.getCheckcodeJqImg());
-            log.info( "系统识别的交强验证码为:" + systemJqCode);
+            log.info("系统识别的交强验证码为:{}", systemJqCode);
             recordResponse.setCheckcodeJq(systemJqCode);
             // 识别验证码
             String systemSyCode = exteriorUtilsRequest.captchaIdentify(recordResponse.getCheckcodeSyImg());
-            log.info( "系统识别的商业验证码为:" + systemSyCode);
+            log.info("系统识别的商业验证码为:{}", systemSyCode);
             recordResponse.setCheckcodeSy(systemSyCode);
-            recordResponse.getCheckcodeJq().replace("0","o");
-            recordResponse.getCheckcodeSy().replace("0","o");
+            recordResponse.setCheckcodeJq(recordResponse.getCheckcodeJq().replace("0", "o"));
+            recordResponse.setCheckcodeSy(recordResponse.getCheckcodeSy().replace("0", "o"));
             calculationRequest.setTransferVehicle(recordResponse);
 
-            resJson = hbCrawlerRequestComponent.getCalculationResult(calculationRequest, headers);
-            resJsonObj = JSONObject.parseObject(resJson);
-            if (resJsonObj == null) {
-                return HbCrawlerQuoteResultVoBuild.build(quoteVo, null, "恒邦calculation接口返回异常");
+            errorMsg = retryCalculation(calculationRequest, headers);
+            if (errorMsg == null) {
+                return buildErrorResult(quoteVo);
             }
-            errorMsg = resJsonObj.getString("message");
-            status = resJsonObj.getString("status");
         }
 
-        if (errorMsg.equals("成功")) {
-            errorMsg = "成功";
+        if ("成功".equals(errorMsg)) {
             // 5.2 报价第三步,获取报价数据
             proposalResponse = hbCrawlerRequestComponent.carInsureItem(plyappno, headers);
             HbCrawlerOrder hbCrawlerOrder = new HbCrawlerOrder();
@@ -227,6 +227,64 @@ public class HengBangCrawlerRequestImpl implements HengBangCrawlerRequest {
         return HbCrawlerQuoteResultVoBuild.build(quoteVo, proposalResponse, errorMsg);
     }
 
+    /**
+     * 调用报价接口并返回解析结果
+     */
+    private JSONObject callCalculation(HbCrawlerCalculationRequest calculationRequest, HttpHeaders headers) {
+        String resJson = hbCrawlerRequestComponent.getCalculationResult(calculationRequest, headers);
+        return JSONObject.parseObject(resJson);
+    }
+
+    /**
+     * 重试报价并返回错误消息,null表示接口异常
+     */
+    private String retryCalculation(HbCrawlerCalculationRequest calculationRequest, HttpHeaders headers) {
+        JSONObject resJsonObj = callCalculation(calculationRequest, headers);
+        return resJsonObj != null ? resJsonObj.getString("message") : null;
+    }
+
+    /**
+     * 构建异常返回结果
+     */
+    private QuoteResultsVo buildErrorResult(QuoteVo quoteVo) {
+        return HbCrawlerQuoteResultVoBuild.build(quoteVo, null, "恒邦calculation接口返回异常");
+    }
+
+    /**
+     * 获取重复投保场景的建议起保时间(yyyy-MM-dd HH:mm:ss 格式)
+     * 优先从 responseBody.begintimeBi 获取,兜底从 message 正则提取
+     */
+    private String getDuplicateBegintime(JSONObject resJsonObj, String errorMsg) {
+        // 优先从 responseBody.begintimeBi 获取
+        JSONObject responseBody = resJsonObj.getJSONObject("responseBody");
+        if (responseBody != null) {
+            String begintimeBi = responseBody.getString("begintimeBi");
+            if (begintimeBi != null) {
+                return normalizeTimeFormat(begintimeBi);
+            }
+        }
+        // 兼容:从 message 正则提取终保日期
+        return hbCrawlerRequestComponent.extractDuplicateEndTime(errorMsg);
+    }
+
+    /**
+     * 统一时间格式为 yyyy-MM-dd HH:mm:ss
+     */
+    private String normalizeTimeFormat(String time) {
+        if (time == null) {
+            return null;
+        }
+        // "2026-07-23" → "2026-07-23 00:00:00"
+        if (time.length() <= 10) {
+            return time + " 00:00:00";
+        }
+        // "2025-12-14 16:00" → "2025-12-14 16:00:00"
+        if (time.length() == 16) {
+            return time + ":00";
+        }
+        return time;
+    }
+
     /**
      * 注释
      *

+ 1 - 1
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeOrdersServiceImpl.java

@@ -202,7 +202,7 @@ public class InsFeeOrdersServiceImpl extends ServiceImpl<InsFeeOrdersMapper, Ins
         // 加投直接乘
         BigDecimal addThrow = premium.multiply(addThrowRatio).setScale(scale, RoundingMode.HALF_EVEN);
         // 出口直接乘
-        BigDecimal export = premium.multiply(exportRatio).setScale(scale, RoundingMode.DOWN);
+        BigDecimal export = premium.multiply(exportRatio).setScale(2, RoundingMode.DOWN);
         BigDecimal exportKeepPoint = premium.multiply(exportKeepPointRatio).setScale(scale, RoundingMode.DOWN);
         // 留点比例直接乘, modify by lipf ,留点比例在infFeeOrder中计算得到。这里直接使用 2026年6月16日17:32:09, 为了保持金额一致,留点比例不适用百分比乘积,而是使用金额相减
         // BigDecimal keepPoint = premium.multiply(keepPointRatio).setScale(scale, RoundingMode.HALF_EVEN);

+ 5 - 0
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/state/config/OrderStateConfig.java

@@ -55,6 +55,11 @@ public class OrderStateConfig extends StateMachineConfigurerAdapter<OrderState.O
                 .withExternal()
                 // 人工处理 -> 待缴费
                 .source(OrderState.OrderStateEnum.STAFF_PROCESS).target(OrderState.OrderStateEnum.PAY_PENDING).event(OrderState.OrderStateEvent.RENG_PAY_PENDING_EVENT)
+                .and()
+                .withExternal()
+                // 人工处理 -> 核保失败
+                .source(OrderState.OrderStateEnum.STAFF_PROCESS).target(OrderState.OrderStateEnum.AUDIT_FAIL).event(OrderState.OrderStateEvent.AUDIT_FAILED_EVENT)
+
         ;
 
         return builder.build();

+ 1 - 0
tenant/insurance/quotation-summary/src/main/resources/mapper/InsOrdersMapper.xml

@@ -836,6 +836,7 @@
         io.order_status,
         io.create_time,
         io.create_by,
+        io.error_message,
         ioci.license_no,
         ioci.vin_no,
         owner_u.name as owner_name,

+ 60 - 0
tenant/organization/src/main/java/com/jzg/organization/controller/InsFeeFollowOrderReconciliationController.java

@@ -0,0 +1,60 @@
+package com.jzg.organization.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.jzg.commons.aop.OperatorTrajectory;
+import com.jzg.commons.constants.OperationTypeEnum;
+import com.jzg.commons.core.base.BaseController;
+import com.jzg.commons.core.page.HttpResult;
+import com.jzg.commons.entity.dto.AgreementAddParam;
+import com.jzg.commons.entity.finance.dto.InsFeeFollowOrderReconciliationSaveDTO;
+import com.jzg.commons.entity.finance.po.InsFeeFollowOrderReconciliation;
+import com.jzg.organization.mapper.PtlAgreementMapper;
+import com.jzg.organization.service.InsFeeFollowOrderReconciliationService;
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**
+ * 手续费跟单费对账 前端控制器
+ */
+@RestController
+@RequestMapping("/followReconciliation")
+public class InsFeeFollowOrderReconciliationController {
+
+    @Autowired
+    private InsFeeFollowOrderReconciliationService reconciliationService;
+    @Autowired
+    private BaseController baseController;
+
+
+    /**
+     * 跟单对账金额修改
+     * @param saveDTO
+     * @return
+     */
+    @PostMapping("/saveOrUpdate")
+    public HttpResult<String> saveOrUpdate(@RequestBody InsFeeFollowOrderReconciliationSaveDTO saveDTO) {
+        QueryWrapper<InsFeeFollowOrderReconciliation> insFeeFollowOrderReconciliationQueryWrapper = new QueryWrapper<>();
+        insFeeFollowOrderReconciliationQueryWrapper.eq("year", saveDTO.getYear())
+                .eq("month", saveDTO.getMonth())
+                .eq("partner_company_id", saveDTO.getPartnerCompanyId())
+                .eq("system_code", baseController.getSystemCode())
+                .last("LIMIT 1"); // 取一条即可,或者根据业务取最新的
+        InsFeeFollowOrderReconciliation insFeeFollowOrderReconciliation = reconciliationService.getOne(insFeeFollowOrderReconciliationQueryWrapper);
+
+        if (null != insFeeFollowOrderReconciliation){
+            insFeeFollowOrderReconciliation.setReconciliationAmount(saveDTO.getReconciliationAmount());
+            insFeeFollowOrderReconciliation.setFalselyIncreasedDifference(saveDTO.getFalselyIncreasedDifference());
+            insFeeFollowOrderReconciliation.setFalselyIncreasedReason(saveDTO.getFalselyIncreasedReason());
+            reconciliationService.updateById(insFeeFollowOrderReconciliation);
+        }else{
+            reconciliationService.saveReconciliation(saveDTO);
+        }
+        return HttpResult.ok("修改成功");
+    }
+
+}

+ 13 - 0
tenant/organization/src/main/java/com/jzg/organization/mapper/InsFeeFollowOrderReconciliationMapper.java

@@ -0,0 +1,13 @@
+package com.jzg.organization.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.jzg.commons.entity.finance.po.InsFeeFollowOrderReconciliation;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 对账表 Mapper接口
+ */
+@Mapper
+public interface InsFeeFollowOrderReconciliationMapper extends BaseMapper<InsFeeFollowOrderReconciliation> {
+
+}

+ 5 - 0
tenant/organization/src/main/java/com/jzg/organization/mapper/InsPlyIncomeInvoiceSettlementMapper.java

@@ -5,6 +5,7 @@ import com.jzg.commons.entity.finance.po.InsPlyIncomeInvoiceSettlement;
 import com.jzg.commons.entity.finance.vo.SettlementVo;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 import java.util.List;
 
@@ -18,4 +19,8 @@ public interface InsPlyIncomeInvoiceSettlementMapper extends BaseMapper<InsPlyIn
      * @date 2026/6/30 15:39
      */
     SettlementVo querySettlementAndDiff(@Param("settlementIds") List<String> settlementIds);
+
+    @Select("select * from ins_ply_income_invoice_settlement ipiis where ipiis.invoice_id = #{invoiceId,jdbcType=VARCHAR} order by ipiis.create_time desc ")
+    List<InsPlyIncomeInvoiceSettlement> querySettlementRecent(@Param("invoiceId") String invoiceId);
+
 }

+ 28 - 0
tenant/organization/src/main/java/com/jzg/organization/service/InsFeeFollowOrderReconciliationService.java

@@ -0,0 +1,28 @@
+package com.jzg.organization.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.jzg.commons.entity.finance.dto.InsFeeFollowOrderReconciliationSaveDTO;
+import com.jzg.commons.entity.finance.po.InsFeeFollowOrderReconciliation;
+import com.jzg.commons.entity.finance.vo.InsFeeFollowOrderReconciliationVO;
+
+/**
+ * 对账记录 业务接口
+ */
+public interface InsFeeFollowOrderReconciliationService extends IService<InsFeeFollowOrderReconciliation> {
+
+    /**
+     * 新增对账记录
+     */
+    boolean saveReconciliation(InsFeeFollowOrderReconciliationSaveDTO saveDTO);
+
+    /**
+     * 修改对账记录
+     */
+    boolean updateReconciliation(InsFeeFollowOrderReconciliationSaveDTO saveDTO);
+
+    /**
+     * 根据ID查询详情
+     */
+    InsFeeFollowOrderReconciliationVO getDetailById(Long id);
+}

+ 53 - 0
tenant/organization/src/main/java/com/jzg/organization/service/impl/InsFeeFollowOrderReconciliationServiceImpl.java

@@ -0,0 +1,53 @@
+package com.jzg.organization.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.jzg.commons.core.base.BaseController;
+import com.jzg.commons.entity.finance.dto.InsFeeFollowOrderReconciliationSaveDTO;
+import com.jzg.commons.entity.finance.po.InsFeeFollowOrderReconciliation;
+import com.jzg.commons.entity.finance.vo.InsFeeFollowOrderReconciliationVO;
+import com.jzg.organization.mapper.InsFeeFollowOrderReconciliationMapper;
+import com.jzg.organization.service.InsFeeFollowOrderReconciliationService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 对账记录 业务实现类
+ */
+@Service
+public class InsFeeFollowOrderReconciliationServiceImpl
+        extends ServiceImpl<InsFeeFollowOrderReconciliationMapper, InsFeeFollowOrderReconciliation>
+        implements InsFeeFollowOrderReconciliationService {
+
+    @Autowired
+    private BaseController baseController;
+
+    @Override
+    public boolean saveReconciliation(InsFeeFollowOrderReconciliationSaveDTO saveDTO) {
+        InsFeeFollowOrderReconciliation entity = new InsFeeFollowOrderReconciliation();
+        entity.setSystemCode(baseController.getSystemCode());
+        BeanUtils.copyProperties(saveDTO, entity);
+        return this.save(entity);
+    }
+
+    @Override
+    public boolean updateReconciliation(InsFeeFollowOrderReconciliationSaveDTO saveDTO) {
+        if (saveDTO.getId() == null) {
+            throw new IllegalArgumentException("修改操作ID不能为空");
+        }
+        InsFeeFollowOrderReconciliation entity = new InsFeeFollowOrderReconciliation();
+        BeanUtils.copyProperties(saveDTO, entity);
+        return this.updateById(entity);
+    }
+
+    @Override
+    public InsFeeFollowOrderReconciliationVO getDetailById(Long id) {
+        InsFeeFollowOrderReconciliation entity = this.getById(id);
+        if (entity == null) {
+            return null;
+        }
+        InsFeeFollowOrderReconciliationVO vo = new InsFeeFollowOrderReconciliationVO();
+        BeanUtils.copyProperties(entity, vo);
+        return vo;
+    }
+}

+ 61 - 18
tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java

@@ -6,6 +6,7 @@ import cn.hutool.core.date.DateTime;
 import cn.hutool.core.lang.tree.Tree;
 import cn.hutool.core.lang.tree.TreeNodeConfig;
 import cn.hutool.core.lang.tree.TreeUtil;
+import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.excel.EasyExcel;
@@ -96,6 +97,9 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
     @Autowired
     private InsFeeFollowOrderMapper insFeeFollowOrderMapper;
 
+    @Autowired
+    private InsFeeFollowOrderReconciliationMapper insFeeFollowOrderReconciliationMapper;
+
     @Autowired
     private InsPlyFollowInvoiceLinkMapper insPlyFollowInvoiceLinkMapper;
 
@@ -324,7 +328,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         List<InsPlyIncomeOrder> res = page.getRecords().stream()
                 .map(action -> new InsPlyIncomeOrder(action.getId(), action.getOrderNo())).toList();
         BigDecimal totalAmount = page.getRecords().stream()
-                .map(action -> new BigDecimal(Objects.toString(action.getJyReceivablePremium(), "0"))).reduce(BigDecimal.ZERO, BigDecimal::add);
+                .map(action -> new BigDecimal(Objects.toString(action.getReceivableAmount(), "0"))).reduce(BigDecimal.ZERO, BigDecimal::add);
 
         InsPlyIncomeVO vo = new InsPlyIncomeVO(null, res,Objects.toString(totalAmount,"0"));
         log.info("获取私有/平台协议手续费应收列表的id集合。receivableQueryVo=[{}]. ids.size=[{}]", JSONUtil.toJsonStr(receivableQueryVo), CollUtil.size(res));
@@ -1478,7 +1482,8 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             default -> null;
         };
         // 四舍五入
-        return result.setScale(2, BigDecimal.ROUND_HALF_UP);
+//        return result.setScale(2, BigDecimal.ROUND_HALF_UP);
+        return result;
     }
 
     /**
@@ -3762,6 +3767,9 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
     @Transactional(rollbackFor = Exception.class)
     public InvoiceingResult followInvoicing(FollowInvoiceVo vo) {
         log.info("跟单费开票业务开始:参数=[{}]", JSONUtil.toJsonStr(vo));
+        if (!NumberUtil.isNumber(vo.getTaxPoint())){
+            throw new SystemException("请输入正确的税点");
+        }
 
         // 校验明细列表
         List<InsFeeFollowOrderVo> details = vo.getDetails();
@@ -3918,10 +3926,10 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             return CollUtil.newArrayList();
         }
         if (StrUtil.isBlank(followInvoicePageListVo.getSearchList().stream().filter(search -> "signYear".equals(search.getName())).findAny().get().getSearch())){
-            return CollUtil.newArrayList();
+            throw new SystemException("请选择年份!");
         }
         if (!StrUtil.contains(followInvoicePageListVo.getSearchList().stream().filter(search -> "signYear".equals(search.getName())).findAny().get().getSearch(), ",")){
-            return CollUtil.newArrayList();
+            throw new SystemException("请选择年份!");
         }
         FollowInvoicePageListVo.SearchVO searchYear = followInvoicePageListVo.getSearchList().stream().filter(search -> "signYear".equals(search.getName())).findFirst().orElse(new FollowInvoicePageListVo.SearchVO());
         Integer startYear = Integer.parseInt(searchYear.getSearch().split(",")[0]);
@@ -3949,8 +3957,8 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                         .collect(Collectors.toMap(FollowInvoicePageListVo.SearchVO::getName, Function.identity(), (oldItem, newItem) -> oldItem));
                 Set<String> names = searchVOMap.keySet();
 
-                // 保险公司
-                Predicate<InsPlyIncomeDto> companyIdPredicate = insPlyIncome -> {
+                // 分支保险公司
+                Predicate<InsPlyIncomeDto> partnerCompanyIdPredicate = insPlyIncome -> {
                     if (!names.contains(FollowInvoicePageListVo.SearchVO.companyId)) {
                         return true;
                     }
@@ -3965,21 +3973,21 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                     }
                     if ("等于".equalsIgnoreCase(type) || "包含".equalsIgnoreCase(type)) {
                         List<String> companyIds = Arrays.asList(search.split(","));
-                        return companyIds.contains(insPlyIncome.getCompanyId());
+                        return companyIds.contains(insPlyIncome.getPartnerCompanyId());
                     }
                     if ("不等于".equalsIgnoreCase(type) || "不包含".equalsIgnoreCase(type)) {
                         List<String> companyIds = Arrays.asList(search.split(","));
-                        return !companyIds.contains(insPlyIncome.getCompanyId());
+                        return !companyIds.contains(insPlyIncome.getPartnerCompanyId());
                     }
                     return true;
                 };
 
                 // AND / OR 组合逻辑(和代码A完全一致)
                 if ("and".equalsIgnoreCase(followInvoicePageListVo.getLogicJudge())) {
-                    Predicate<InsPlyIncomeDto> and = companyIdPredicate;
+                    Predicate<InsPlyIncomeDto> and = partnerCompanyIdPredicate;
                     filterIncomes = incomes.stream().filter(and).toList();
                 } else if ("or".equalsIgnoreCase(followInvoicePageListVo.getLogicJudge())) {
-                    Predicate<InsPlyIncomeDto> or = companyIdPredicate;
+                    Predicate<InsPlyIncomeDto> or = partnerCompanyIdPredicate;
                     filterIncomes = incomes.stream().filter(or).toList();
                 }
             }
@@ -4163,6 +4171,8 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                                                    String partnerCompanyId,
                                                    Map<Integer, BigDecimal> monthReceivableMap,
                                                    Map<String, BigDecimal> invoicedMap) {
+
+        String systemCode = baseController.getSystemCode();
         // 获取当月应收保费,默认为0
         BigDecimal receivable = monthReceivableMap.getOrDefault(month, BigDecimal.ZERO);
         // 获取当月已开票金额,默认为0
@@ -4185,6 +4195,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         queryWrapper.eq("year", year)
                 .eq("month", month)
                 .eq("partner_company_id", partnerCompanyId)
+                .eq("system_code", systemCode)
                 .last("LIMIT 1"); // 取一条即可,或者根据业务取最新的
         InsFeeFollowOrder dbOrder = insFeeFollowOrderMapper.selectOne(queryWrapper);
         if (dbOrder != null) {
@@ -4196,10 +4207,23 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             // 现在按wwq的要求改成:未开票金额 = 对账金额 - 已开票金额
             vo.setUninvoiced(dbOrder.getReconciliationAmount().subtract(invoiced));
         } else {
-            // 数据库无记录,使用默认值或DTO里的值
-            vo.setReconciliationAmount(null);
-            vo.setFalselyIncreasedDifference(null);
-            vo.setFalselyIncreasedReason(null);
+            QueryWrapper<InsFeeFollowOrderReconciliation> insFeeFollowOrderReconciliationQueryWrapper = new QueryWrapper<>();
+            insFeeFollowOrderReconciliationQueryWrapper.eq("year", year)
+                    .eq("month", month)
+                    .eq("partner_company_id", partnerCompanyId)
+                    .eq("system_code", systemCode)
+                    .last("LIMIT 1"); // 取一条即可,或者根据业务取最新的
+            InsFeeFollowOrderReconciliation insFeeFollowOrderReconciliation = insFeeFollowOrderReconciliationMapper.selectOne(insFeeFollowOrderReconciliationQueryWrapper);
+            if (null != insFeeFollowOrderReconciliation){
+                vo.setReconciliationAmount(insFeeFollowOrderReconciliation.getReconciliationAmount());
+                vo.setFalselyIncreasedDifference(insFeeFollowOrderReconciliation.getFalselyIncreasedDifference());
+                vo.setFalselyIncreasedReason(insFeeFollowOrderReconciliation.getFalselyIncreasedReason());
+            }else{
+                // 数据库无记录,使用默认值或DTO里的值
+                vo.setReconciliationAmount(null);
+                vo.setFalselyIncreasedDifference(null);
+                vo.setFalselyIncreasedReason(null);
+            }
         }
         return vo;
     }
@@ -4422,7 +4446,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                 BigDecimal receivableSupervisePremium = action.getReceivableSupervisePremium()  != null ? action.getReceivableSupervisePremium(): BigDecimal.ZERO;
 //                BigDecimal overinflatedAmount = action.getOverinflatedAmount() != null? action.getOverinflatedAmount(): BigDecimal.ZERO;
                 // 待结算金额 = 开票金额 - 已收金额
-                BigDecimal remainSettlementAmount = receivableSupervisePremium.subtract(settlementAmount);
+                BigDecimal remainSettlementAmount = receivableSupervisePremium.subtract(BigDecimalUtil.add(settlementAmount, settlementPaymentDifference));
                 // 设置已结算的金额
                 action.setSettlementAmount(settlementAmount);
                 // 设置待结算金额
@@ -5366,7 +5390,11 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         List<CalRes> sxfList = baseMapper.querySettledAmount(systemCode, queryVo.getInvoiceStartTime(), queryVo.getInvoiceEndTime(), queryVo.getAgreementType(), CollUtil.newArrayList("1", "3"));
         List<CalRes> gdfList = baseMapper.querySettledAmount(systemCode, queryVo.getInvoiceStartTime(), queryVo.getInvoiceEndTime(), queryVo.getAgreementType(), CollUtil.newArrayList("2", "4"));
         Map<String, BigDecimal> sxfSettledAmountMap = CollUtil.isNotEmpty(sxfList) ? sxfList.stream().collect(Collectors.toMap(CalRes::getCompanyId, CalRes::getSettlement, (o1,o2)->o1)) : new HashMap<>();
+        // 手续费的回款差额汇总
+        Map<String, BigDecimal> sxfSettledDiffAmountMap = CollUtil.isNotEmpty(sxfList) ? sxfList.stream().collect(Collectors.toMap(CalRes::getCompanyId, CalRes::getOverinflatedAmount, (o1,o2)->o1)) : new HashMap<>();
         Map<String, BigDecimal> gdfSettledAmountMap = CollUtil.isNotEmpty(gdfList) ? gdfList.stream().collect(Collectors.toMap(CalRes::getCompanyId, CalRes::getSettlement, (o1,o2)->o1)) : new HashMap<>();
+        // 跟单费的回款差额汇总
+        Map<String, BigDecimal> gdfSettledDiffAmountMap = CollUtil.isNotEmpty(gdfList) ? gdfList.stream().collect(Collectors.toMap(CalRes::getCompanyId, CalRes::getOverinflatedAmount, (o1,o2)->o1)) : new HashMap<>();
 
         // 计算已开票和未开票
         for (String companyId : companyMap.keySet()) {
@@ -5383,16 +5411,17 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
 
             CompanySuperviseSettlementReportDto dto;
             dto = companyMap.get(companyId);
-            companySuperviseSettlementReportDto.setSxfUnInvoicedAmount(BigDecimalUtil.subtract(new BigDecimal(dto.getSuperviseFee()),sxf).toString());
-            companySuperviseSettlementReportDto.setGdfUnInvoicedAmount(BigDecimalUtil.subtract(new BigDecimal(dto.getFollowFee()),gdf).toString());
+            companySuperviseSettlementReportDto.setSxfUnInvoicedAmount(BigDecimalUtil.subtract(new BigDecimal(dto.getSuperviseFee()),BigDecimalUtil.subtract(sxf, new BigDecimal(dto.getTotalOverinflatedAmount()))).toString());
+            companySuperviseSettlementReportDto.setGdfUnInvoicedAmount(BigDecimalUtil.subtract(new BigDecimal(dto.getFollowFee()),BigDecimalUtil.subtract(gdf,new BigDecimal(dto.getTotalOverinflatedAmount()))).toString());
             companySuperviseSettlementReportDto.setPtUnInvoicedAmount(BigDecimal.ZERO.toString());
 
             BigDecimal sxfS = sxfSettledAmountMap.getOrDefault(companyId, BigDecimal.ZERO);
             BigDecimal gdfS = gdfSettledAmountMap.getOrDefault(companyId, BigDecimal.ZERO);
             BigDecimal overinflatedAmount = sxfOverinflatedAmountMap.getOrDefault(companyId, BigDecimal.ZERO);
             companySuperviseSettlementReportDto.setSxfSettledAmount(Objects.toString(sxfS, BigDecimal.ZERO+""));
-            companySuperviseSettlementReportDto.setSxfUnSettledAmount(BigDecimalUtil.subtract(sxf,sxfS).toString());
+            companySuperviseSettlementReportDto.setSxfUnSettledAmount(BigDecimalUtil.subtract(sxf,BigDecimalUtil.add(sxfS,sxfSettledDiffAmountMap.getOrDefault(companyId, BigDecimal.ZERO))).toString());
             companySuperviseSettlementReportDto.setTotalOverinflatedAmount(Objects.toString(overinflatedAmount, BigDecimal.ZERO+""));
+            companySuperviseSettlementReportDto.setSettlementPaymentDifference(Objects.toString(sxfSettledDiffAmountMap.getOrDefault(companyId, BigDecimal.ZERO)) );
 
             companySuperviseSettlementReportDto.setGdfSettledAmount(Objects.toString(gdfS, BigDecimal.ZERO+""));
             companySuperviseSettlementReportDto.setGdfUnSettledAmount(BigDecimalUtil.subtract(gdf,gdfS).toString());
@@ -5551,6 +5580,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             tree.putExtra("gdfSettledAmount",dto.getGdfSettledAmount());
             tree.putExtra("gdfUnSettledAmount",dto.getGdfUnSettledAmount());
             tree.putExtra("totalOverinflatedAmount",dto.getTotalOverinflatedAmount());
+            tree.putExtra("settlementPaymentDifference",dto.getSettlementPaymentDifference());
         });
         log.info("树形结构构建:一级数据[{}]个", CollUtil.size(build));
         return build;
@@ -5948,6 +5978,19 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         String userName = baseController.getUserName();
         String systemCode = baseController.getSystemCode();
         log.info("租户[{}]下的用户[{}]标识发票[{}]为结算完成", systemCode, userName, invoiceId);
+
+        List<InsPlyIncomeInvoiceSettlement> insPlyIncomeInvoiceSettlements =  insPlyIncomeInvoiceSettlementMapper.querySettlementRecent(invoiceId);
+        InsPlyIncomeInvoice insPlyIncomeInvoice = insPlyIncomeInvoiceMapper.selectById(invoiceId);
+
+        // 标记结算完成的时候,将未结算金额汇总 到最后一次结算的回款差额里面  lipf 2026年7月7日10:53:47
+        BigDecimal settlementAmount =  insPlyIncomeInvoiceSettlements.stream().map(action-> BigDecimalUtil.add(action.getSettlementPaymentDifference(), action.getActualReceivedAmount()))
+                .reduce(BigDecimal.ZERO,BigDecimal::add);
+        BigDecimal subtract = BigDecimalUtil.subtract(insPlyIncomeInvoice.getReceivableSupervisePremium(), settlementAmount);
+        if(subtract.compareTo(BigDecimal.ZERO) != 0){
+            InsPlyIncomeInvoiceSettlement insPlyIncomeInvoiceSettlement = insPlyIncomeInvoiceSettlements.get(0);
+            insPlyIncomeInvoiceSettlement.setSettlementPaymentDifference(BigDecimalUtil.add(subtract,insPlyIncomeInvoiceSettlement.getSettlementPaymentDifference()));
+            insPlyIncomeInvoiceSettlementMapper.updateById(insPlyIncomeInvoiceSettlement);
+        }
         return insPlyIncomeInvoiceMapper.update(null, new LambdaUpdateWrapper<InsPlyIncomeInvoice>()
                 .set(InsPlyIncomeInvoice::getStatus,"1")
                 .set(InsPlyIncomeInvoice::getUpdateBy,userName)

+ 3 - 2
tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

@@ -2002,12 +2002,13 @@
     <select id="querySettledAmount" resultType="com.jzg.organization.entity.dto.CalRes">
         select
         a.company_id ,
-        sum(COALESCE(a.actual_received_amount, 0)) as settlement
+        sum(COALESCE(a.actual_received_amount, 0)) as settlement,sum(a.overinflatedAmount) overinflatedAmount
         from
         (
         select distinct ins.id,
         ipi.company_id ,
-        COALESCE(ins.actual_received_amount, 0) as actual_received_amount
+        COALESCE(ins.actual_received_amount, 0) as actual_received_amount,
+        COALESCE(ins.settlement_payment_difference,0) as overinflatedAmount
         from ins_ply_income_invoice_settlement ins
         inner join ins_ply_income_invoice inc
         on ins.invoice_id = inc.id