Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

lixiaolong 2 месяцев назад
Родитель
Сommit
f68c7c024b
16 измененных файлов с 395 добавлено и 63 удалено
  1. 6 0
      commons/src/main/java/com/jzg/commons/entity/dto/RulesGroupParam.java
  2. 8 3
      commons/src/main/java/com/jzg/commons/entity/finance/po/InsPlyIncome.java
  3. 6 0
      commons/src/main/java/com/jzg/commons/entity/finance/vo/InvoiceRecordQueryVo.java
  4. 5 0
      commons/src/main/java/com/jzg/commons/entity/finance/vo/InvoiceRecordResult.java
  5. 19 0
      platform/src/main/java/com/jzg/controller/EsmInsCompanyController.java
  6. 10 0
      platform/src/main/java/com/jzg/service/EsmInsCompanyService.java
  7. 45 0
      platform/src/main/java/com/jzg/service/impl/EsmInsCompanyServiceImpl.java
  8. 0 4
      tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeAuditServiceImpl.java
  9. 7 0
      tenant/organization/src/main/java/com/jzg/organization/client/EsmInsCompanyClient.java
  10. 2 1
      tenant/organization/src/main/java/com/jzg/organization/controller/ReceivableController.java
  11. 26 5
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementCostServiceImpl.java
  12. 161 34
      tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementUndwrtRulesServiceImpl.java
  13. 80 9
      tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java
  14. 2 2
      tenant/organization/src/main/resources/mapper/InsFeeFollowOrderMapper.xml
  15. 1 1
      tenant/organization/src/main/resources/mapper/PtlAgreementUndwrtRulesAttrLinkMapper.xml
  16. 17 4
      tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

+ 6 - 0
commons/src/main/java/com/jzg/commons/entity/dto/RulesGroupParam.java

@@ -12,6 +12,9 @@ import java.util.List;
 @Data
 public class RulesGroupParam {
 
+    @Schema(description = "规则ID(编辑已有规则时传入,与后端规则一一对应)")
+    private String id;
+
     @Schema(description = "并且规则属性")
     @NotEmpty(message = "规则属性不能为空")
     private List<PtlAgreementUndwrtRulesAttrLink> rulesAttrList;
@@ -19,4 +22,7 @@ public class RulesGroupParam {
     @Schema(description = "费用属性")
     private List<PtlAgreementUndwrtRulesAttr>  costsAttrLinks;
 
+    @Schema(description = "人工输入描述")
+    private String inputDescription;
+
 }

+ 8 - 3
commons/src/main/java/com/jzg/commons/entity/finance/po/InsPlyIncome.java

@@ -82,11 +82,17 @@ public class InsPlyIncome extends BaseModel {
     @ExcelProperty("保司名称")
     private String companyName;
 
-    @Schema(description = "保司名称")
+    @Schema(description = "保险机构(多级名称)")
     @TableField(exist = false)
-    @ExcelProperty("保司名称")
+    @ExcelProperty("保险机构(多级名称)")
     private String partnerCompanyName;
 
+    @Schema(description = "保险机构")
+    @TableField(exist = false)
+    @ExcelProperty("保险机构")
+    private String partnerCompanySimplyName;
+
+
     @Schema(description = "协议Id")
     @ExcelProperty("协议Id")
     @ExcelIgnore
@@ -387,7 +393,6 @@ public class InsPlyIncome extends BaseModel {
     @ExcelProperty("非车应收金额")
     private BigDecimal jyTotalPremiums;
 
-    @TableField(exist = false)
     @Schema(description = "合作保险公司ID")
     @ExcelIgnore
     private String partnerCompanyId;

+ 6 - 0
commons/src/main/java/com/jzg/commons/entity/finance/vo/InvoiceRecordQueryVo.java

@@ -21,6 +21,12 @@ public class InvoiceRecordQueryVo extends PageRequest {
      */
     private String companyId;
 
+    /**
+     * 保险公司关联的保险公司,
+     * 保险公司以及其父保险公司的id, 以及其所有的子公司
+     */
+    private List<String> companyIds;
+
     /**
      * 开票类型
      */

+ 5 - 0
commons/src/main/java/com/jzg/commons/entity/finance/vo/InvoiceRecordResult.java

@@ -40,6 +40,11 @@ public class InvoiceRecordResult extends PageRequest {
      */
     private String companyAllName;
 
+    /**
+     * 父级保险公司的名称
+     */
+    private String parentCompanyName;
+
     /**
      * 开票方
      */

+ 19 - 0
platform/src/main/java/com/jzg/controller/EsmInsCompanyController.java

@@ -2,6 +2,8 @@ package com.jzg.controller;
 
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.json.JSONUtil;
 import com.alibaba.nacos.client.naming.utils.CollectionUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.jzg.commons.core.base.BaseController;
@@ -478,4 +480,21 @@ public class EsmInsCompanyController extends BaseController {
     public HttpResult<Map<String,EsmInsCompany>> queryAllCompanyMap(){
         return HttpResult.ok(esmInsCompanyService.queryAllCompanyMap());
     }
+
+    /**
+     * 查询保险公司关联的所有子公司和总公司
+     *
+     * @param companyId 保险公司的id
+     * @return HttpResult<List<String>>
+     * @author lipf
+     * @date 2026年7月31日09:29:26
+     */
+    @Operation(summary = "查询保险公司关联的所有子公司和总公司")
+    @GetMapping("/queryRelatedCompanyIds")
+    HttpResult<List<String>> queryRelatedCompanyIds(@RequestParam("companyId") String companyId){
+        List<String> companyIds = esmInsCompanyService.queryRelatedCompanyIds(companyId);
+        companyIds = companyIds.stream().distinct().toList();
+        log.info("查询保险公司关联的所有子公司和总公司: companyId=[{}], companyIds=[{}],companyIds.size=[{}]", companyId, JSONUtil.toJsonStr(companyIds), CollUtil.size(companyIds));
+        return HttpResult.ok(companyIds);
+    }
 }

+ 10 - 0
platform/src/main/java/com/jzg/service/EsmInsCompanyService.java

@@ -161,6 +161,16 @@ public interface EsmInsCompanyService extends IService<EsmInsCompany> {
      * @date 2026/5/23 9:12
      */
     Map<String,EsmInsCompany> queryAllCompanyMap();
+
+    /**
+     * 保险公司以及其父保险公司的id
+     *
+     * @param companyId 保险公司的id
+     * @return HttpResult<List<String>>
+     * @author lipf
+     * @date 2026年7月31日09:29:26
+     */
+    List<String> queryRelatedCompanyIds(String companyId);
 }
 
 

+ 45 - 0
platform/src/main/java/com/jzg/service/impl/EsmInsCompanyServiceImpl.java

@@ -2,6 +2,7 @@ package com.jzg.service.impl;
 
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -450,6 +451,50 @@ public class EsmInsCompanyServiceImpl extends ServiceImpl<EsmInsCompanyMapper, E
         return fullPath;
     }
 
+    /**
+     * 保险公司以及其父保险公司的id
+     *
+     * @param companyId 保险公司的id
+     * @return HttpResult<List<String>>
+     * @author lipf
+     * @date 2026年7月31日09:29:26
+     */
+    @Override
+    public List<String> queryRelatedCompanyIds(String companyId) {
+        List<String> companyIds = new  ArrayList<>();
+        companyIds.add(companyId);
+        LambdaQueryWrapper<EsmInsCompany> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(EsmInsCompany::getParentId, companyId);
+        List<EsmInsCompany> esmInsCompanies = baseMapper.selectList(queryWrapper);
+        for (EsmInsCompany esmInsCompany : esmInsCompanies) {
+            companyIds.add(esmInsCompany.getId());
+            LambdaQueryWrapper<EsmInsCompany> wrapper = new LambdaQueryWrapper<>();
+            wrapper.eq(EsmInsCompany::getParentId, esmInsCompany.getId());
+            List<EsmInsCompany> childCompany = baseMapper.selectList(wrapper);
+            childCompany.stream().map(EsmInsCompany::getId).forEach(companyIds::add);
+        }
+        esmInsCompanies.stream().map(EsmInsCompany::getId).forEach(companyIds::add);
+        EsmInsCompany esmInsCompany = baseMapper.selectById(companyId);
+        if(esmInsCompany == null){
+           return companyIds;
+        }
+        companyId = esmInsCompany.getParentId();
+        if(StrUtil.isEmpty(companyId) || companyId.equals("0")){
+            return companyIds;
+        }
+        companyIds.add(esmInsCompany.getParentId());
+
+        esmInsCompany = baseMapper.selectById(companyId);
+        if(esmInsCompany == null){
+            return companyIds;
+        }
+        companyId = esmInsCompany.getParentId();
+        if(StrUtil.isEmpty(companyId) || companyId.equals("0")){
+            return companyIds;
+        }
+        companyIds.add(esmInsCompany.getParentId());
+        return companyIds;
+    }
 }
 
 

+ 0 - 4
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/service/impl/InsFeeAuditServiceImpl.java

@@ -1209,7 +1209,3 @@ public class InsFeeAuditServiceImpl extends ServiceImpl<InsFeeAuditMapper, InsFe
         return res.getRecords();
     }
 }
-
-
-
-

+ 7 - 0
tenant/organization/src/main/java/com/jzg/organization/client/EsmInsCompanyClient.java

@@ -79,4 +79,11 @@ public interface EsmInsCompanyClient {
     @PostMapping("/esmInsCompany/getTopCompanyId")
     HttpResult getTopCompanyId(@RequestSingleParam("companyId") String companyId);
 
+    /**
+     * 查询保险公司关联的所有子公司和总公司
+     * @author lipf
+     * @date 2026/7/31 9:44
+     */
+    @GetMapping("/esmInsCompany/queryRelatedCompanyIds")
+    HttpResult<List<String>> queryRelatedCompanyIds(@RequestParam("companyId") String companyId);
 }

+ 2 - 1
tenant/organization/src/main/java/com/jzg/organization/controller/ReceivableController.java

@@ -12,6 +12,7 @@ import com.jzg.commons.entity.finance.dto.ReceiverSettlementReportDto;
 import com.jzg.commons.entity.finance.po.*;
 import com.jzg.commons.entity.finance.vo.*;
 import com.jzg.commons.entity.orders.po.InsOrderAdjust;
+import com.jzg.commons.entity.po.EsmInsCompany;
 import com.jzg.commons.request.RequestSingleParam;
 import com.jzg.commons.util.AssertionUtils;
 import com.jzg.organization.service.ReceivableService;
@@ -366,7 +367,7 @@ public class ReceivableController {
 
     @PostMapping("getReceivableCompany")
     @Operation(summary = "获取保险公司")
-    public HttpResult getReceivableCompany(@RequestBody InvoicingVo invoicingVo){
+    public HttpResult<List<EsmInsCompany>> getReceivableCompany(@RequestBody InvoicingVo invoicingVo){
         return HttpResult.ok(receivableService.getReceivableCompany(invoicingVo));
     }
 

+ 26 - 5
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementCostServiceImpl.java

@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.jzg.commons.constants.Constants;
+import com.jzg.commons.constants.ProductsType;
 import com.jzg.commons.constants.ReturnInformation;
 import com.jzg.commons.core.base.BaseController;
 import com.jzg.commons.core.base.StateResult;
@@ -408,10 +409,30 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
             ptlAgreementCost.setProductId(costCopyParam.getProductId());
             ptlAgreementCost.setProductName(costCopyParam.getProductName());
 
-            ptlAgreementCostTypes.forEach(item->{
-                item.setId(IdGenerate.nextId());
-                item.setPtlAgreementCostId(costId);
-            });
+
+            List<PtlAgreementCostType> newPtlAgreementCostTypes = ptlAgreementCostTypes.stream()
+                    .filter(item -> {
+                        String productId = costCopyParam.getProductId();
+                        // 单交剔除 CostType = 商业险
+                        if ("0330".equals(productId)) {
+                            return !"商业险".equals(item.getCostType());
+                        }
+                        // 单商剔除 CostType = 交强险
+                        if ("034001".equals(productId)) {
+                            return !"交强险".equals(item.getCostType());
+                        }
+                        // 单三剔除 CostType = 交强险
+                        if ("034002".equals(productId)) {
+                            return !"交强险".equals(item.getCostType());
+                        }
+                        return true;
+                    })
+                    .peek(item -> {
+                        // 给留存的元素赋值字段
+                        item.setId(IdGenerate.nextId());
+                        item.setPtlAgreementCostId(costId);
+                    })
+                    .collect(Collectors.toList());
 
             ptlAgreementCostRules.forEach(item->{
                 item.setId(IdGenerate.nextId());
@@ -419,7 +440,7 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
             });
 
             ptlAgreementCostMapper.insert(ptlAgreementCost);
-            ptlAgreementCostTypeMapper.insert(ptlAgreementCostTypes);
+            ptlAgreementCostTypeMapper.insert(newPtlAgreementCostTypes);
             ptlAgreementCostRuleMapper.insert(ptlAgreementCostRules);
 
         });

+ 161 - 34
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementUndwrtRulesServiceImpl.java

@@ -3,6 +3,7 @@ package com.jzg.organization.service.impl;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.jzg.commons.entity.dto.AgreementRulesAddParam;
 import com.jzg.commons.entity.dto.AgreementRulesEditParam;
@@ -184,7 +185,10 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
                     agreementUndwrtRulesAttrLinkMapper.insert(andAttrLinks);
                 }
 
-                rules.setRuleDescription(buildDesc(andAttrLinks, undwrtRulesAttrList));
+                // andAttrLinks 为空时不设置 ruleDescription,避免 updateById 覆盖已有数据
+                if (CollUtil.isNotEmpty(andAttrLinks)) {
+                    rules.setRuleDescription(buildDesc(andAttrLinks, undwrtRulesAttrList));
+                }
                 baseMapper.insert(rules);
             }
             return true;
@@ -244,7 +248,8 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
                         .filter(x -> x.getAttrCode().equals(attr.getAttrCode())).findFirst().orElse(null);
                 throw new SystemException(meta.getAttrName() + "规则不能为空,请修改");
             }
-            if (null != attr.getMin() || null != attr.getMax()) {
+            // 支持 min/max 和 minArray 类型的属性值
+            if (null != attr.getMin() || null != attr.getMax() || null != attr.getMinArray()) {
                 attr.setRulesId(rulesId);
                 attr.setId(null);
                 result.add(attr);
@@ -253,6 +258,45 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
         return result;
     }
 
+    /**
+     * 差异合并属性链接:更新已存在的、新增不存在的、删除旧的多余的
+     * 避免全删全插导致逻辑删除堆积大量垃圾数据
+     */
+    private void mergeAttrLinks(List<PtlAgreementUndwrtRulesAttrLink> oldLinks,
+                                List<PtlAgreementUndwrtRulesAttrLink> newLinks) {
+        // 旧链接 attrCode -> link 映射
+        Map<String, PtlAgreementUndwrtRulesAttrLink> oldMap = new LinkedHashMap<>();
+        if (CollUtil.isNotEmpty(oldLinks)) {
+            for (PtlAgreementUndwrtRulesAttrLink link : oldLinks) {
+                oldMap.put(link.getAttrCode(), link);
+            }
+        }
+        // 合并新链接
+        Set<String> keepAttrCodes = new HashSet<>();
+        if (CollUtil.isNotEmpty(newLinks)) {
+            for (PtlAgreementUndwrtRulesAttrLink newLink : newLinks) {
+                keepAttrCodes.add(newLink.getAttrCode());
+                PtlAgreementUndwrtRulesAttrLink oldLink = oldMap.get(newLink.getAttrCode());
+                if (oldLink != null) {
+                    // 已存在:复用旧ID更新
+                    newLink.setId(oldLink.getId());
+                    agreementUndwrtRulesAttrLinkMapper.updateById(newLink);
+                } else {
+                    // 不存在:插入新记录
+                    agreementUndwrtRulesAttrLinkMapper.insert(newLink);
+                }
+            }
+        }
+        // 删除旧链接中新请求里不存在的
+        if (CollUtil.isNotEmpty(oldLinks)) {
+            for (PtlAgreementUndwrtRulesAttrLink oldLink : oldLinks) {
+                if (!keepAttrCodes.contains(oldLink.getAttrCode())) {
+                    agreementUndwrtRulesAttrLinkMapper.deleteById(oldLink.getId());
+                }
+            }
+        }
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean rulesEdit(AgreementRulesEditParam param) {
@@ -267,52 +311,113 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
                 throw new SystemException("批量模式下父规则ID不能为空");
             }
 
+            // 查询协议下所有规则,计算最大orderNum(排除当前parentId下的旧规则)
+            List<AgreementRulesVo> allRules = baseMapper.queryList(param.getAgreementId());
+            int maxOrderNum = 0;
+            if (CollUtil.isNotEmpty(allRules)) {
+                maxOrderNum = allRules.stream()
+                        .filter(r -> !parentId.equals(r.getParentId()))
+                        .mapToInt(r -> r.getOrderNum() != null ? r.getOrderNum() : 0)
+                        .max().orElse(0);
+            }
+
             // 查询旧的所有子规则(按order_num升序,与新增顺序一致)
             List<AgreementRulesVo> oldRules = baseMapper.queryListByParentId(parentId);
             int oldSize = CollUtil.isNotEmpty(oldRules) ? oldRules.size() : 0;
             List<RulesGroupParam> groups = param.getRulesGroups();
 
-            // 1. 按索引匹配:已有规则复用ID做UPDATE,多出的做INSERT
+            // 判断前端是否传了规则ID(用于精确匹配),否则回退索引匹配
+            boolean hasRuleIds = groups.stream().anyMatch(g -> g.getId() != null && !g.getId().isEmpty());
+            Map<String, AgreementRulesVo> oldRuleMap = new LinkedHashMap<>();
+            if (hasRuleIds && CollUtil.isNotEmpty(oldRules)) {
+                for (AgreementRulesVo vo : oldRules) {
+                    oldRuleMap.put(vo.getId(), vo);
+                }
+            }
+            Set<String> matchedOldIds = new HashSet<>();
+
             for (int i = 0; i < groups.size(); i++) {
                 RulesGroupParam group = groups.get(i);
-                boolean isExisting = i < oldSize;
-                // 复用已有规则ID,保持cover_rule_id引用不失效
-                String ruleId = isExisting ? oldRules.get(i).getId() : IdGenerate.nextId();
-
-                // 已有规则需先清除旧的属性关联
-                if (isExisting) {
-                    agreementUndwrtRulesAttrLinkService.remove(new LambdaQueryWrapper<PtlAgreementUndwrtRulesAttrLink>()
-                            .eq(PtlAgreementUndwrtRulesAttrLink::getRulesId, ruleId));
+                String ruleId;
+                boolean isExisting;
+                String oldRuleDescription = null;
+
+                if (hasRuleIds) {
+                    // ID模式:精确匹配
+                    ruleId = group.getId();
+                    isExisting = ruleId != null && !ruleId.isEmpty() && oldRuleMap.containsKey(ruleId);
+                    if (isExisting) {
+                        matchedOldIds.add(ruleId);
+                        oldRuleDescription = oldRuleMap.get(ruleId).getRuleDescription();
+                    } else {
+                        ruleId = IdGenerate.nextId();
+                    }
+                } else {
+                    // 索引模式:回退到按顺序匹配
+                    isExisting = i < oldSize;
+                    if (isExisting) {
+                        AgreementRulesVo oldVo = oldRules.get(i);
+                        ruleId = oldVo.getId();
+                        matchedOldIds.add(ruleId);
+                        oldRuleDescription = oldVo.getRuleDescription();
+                    } else {
+                        ruleId = IdGenerate.nextId();
+                    }
                 }
 
                 List<PtlAgreementUndwrtRulesAttrLink> andAttrLinks = processAndAttrs(group.getRulesAttrList(), undwrtRulesAttrList, ruleId);
-                if (CollUtil.isNotEmpty(andAttrLinks)) {
+
+                // 已有规则做差异比较更新,避免全删全插产生垃圾数据
+                if (isExisting) {
+                    List<PtlAgreementUndwrtRulesAttrLink> oldLinks = agreementUndwrtRulesAttrLinkService.list(
+                            new LambdaQueryWrapper<PtlAgreementUndwrtRulesAttrLink>()
+                                    .eq(PtlAgreementUndwrtRulesAttrLink::getRulesId, ruleId));
+                    mergeAttrLinks(oldLinks, andAttrLinks);
+                } else if (CollUtil.isNotEmpty(andAttrLinks)) {
                     agreementUndwrtRulesAttrLinkMapper.insert(andAttrLinks);
                 }
 
-                PtlAgreementUndwrtRules rules = new PtlAgreementUndwrtRules();
-                rules.setId(ruleId);
-                rules.setOrderNum(i + 1);
-                rules.setStartTime(param.getStartTime());
-                rules.setEndTime(param.getEndTime());
-                rules.setAgreementId(param.getAgreementId());
-                rules.setParentId(parentId);
-                rules.setRuleDescription(buildDesc(andAttrLinks, undwrtRulesAttrList));
+                String inputDesc = group.getInputDescription() != null ? group.getInputDescription() : param.getInputDescription();
+                int currentOrderNum = maxOrderNum + i + 1;
+                // ruleDescription:有新的属性链接则重新生成,否则保留旧值
+                String ruleDescription = CollUtil.isNotEmpty(andAttrLinks)
+                        ? buildDesc(andAttrLinks, undwrtRulesAttrList)
+                        : oldRuleDescription;
 
                 if (isExisting) {
-                    baseMapper.updateById(rules);
+                    // 使用 LambdaUpdateWrapper 显式指定更新字段,避免 updateById 将 null 字段写入 SQL
+                    LambdaUpdateWrapper<PtlAgreementUndwrtRules> updateWrapper = new LambdaUpdateWrapper<>();
+                    updateWrapper.eq(PtlAgreementUndwrtRules::getId, ruleId)
+                            .set(PtlAgreementUndwrtRules::getOrderNum, currentOrderNum)
+                            .set(PtlAgreementUndwrtRules::getStartTime, param.getStartTime())
+                            .set(PtlAgreementUndwrtRules::getEndTime, param.getEndTime())
+                            .set(PtlAgreementUndwrtRules::getAgreementId, param.getAgreementId())
+                            .set(PtlAgreementUndwrtRules::getParentId, parentId)
+                            .set(PtlAgreementUndwrtRules::getInputDescription, inputDesc)
+                            .set(PtlAgreementUndwrtRules::getRuleDescription, ruleDescription);
+                    baseMapper.update(null, updateWrapper);
                 } else {
+                    PtlAgreementUndwrtRules rules = new PtlAgreementUndwrtRules();
+                    rules.setId(ruleId);
+                    rules.setOrderNum(currentOrderNum);
+                    rules.setStartTime(param.getStartTime());
+                    rules.setEndTime(param.getEndTime());
+                    rules.setAgreementId(param.getAgreementId());
+                    rules.setParentId(parentId);
+                    rules.setInputDescription(inputDesc);
+                    rules.setRuleDescription(ruleDescription);
                     baseMapper.insert(rules);
                 }
             }
 
-            // 2. 删除多余的旧规则(新规则数量 < 旧规则数量时才触发)
-            if (oldSize > groups.size()) {
-                for (int i = groups.size(); i < oldSize; i++) {
-                    AgreementRulesVo oldRule = oldRules.get(i);
-                    agreementUndwrtRulesAttrLinkService.remove(new LambdaQueryWrapper<PtlAgreementUndwrtRulesAttrLink>()
-                            .eq(PtlAgreementUndwrtRulesAttrLink::getRulesId, oldRule.getId()));
-                    baseMapper.deleteById(oldRule.getId());
+            // 2. 删除未被匹配的旧规则(本次请求中不存在对应group的旧规则)
+            if (CollUtil.isNotEmpty(oldRules)) {
+                for (AgreementRulesVo oldRule : oldRules) {
+                    if (!matchedOldIds.contains(oldRule.getId())) {
+                        agreementUndwrtRulesAttrLinkService.remove(new LambdaQueryWrapper<PtlAgreementUndwrtRulesAttrLink>()
+                                .eq(PtlAgreementUndwrtRulesAttrLink::getRulesId, oldRule.getId()));
+                        baseMapper.deleteById(oldRule.getId());
+                    }
                 }
             }
 
@@ -323,9 +428,10 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
         PtlAgreementUndwrtRules rules = new PtlAgreementUndwrtRules();
         BeanUtils.copyProperties(param, rules);
 
-        // 删除费用因子
-        agreementUndwrtRulesAttrLinkService.remove(new LambdaQueryWrapper<PtlAgreementUndwrtRulesAttrLink>()
-                .eq(PtlAgreementUndwrtRulesAttrLink::getRulesId, param.getId()));
+        // 查询旧的属性链接,做差异合并而非全删全插
+        List<PtlAgreementUndwrtRulesAttrLink> oldLinks = agreementUndwrtRulesAttrLinkService.list(
+                new LambdaQueryWrapper<PtlAgreementUndwrtRulesAttrLink>()
+                        .eq(PtlAgreementUndwrtRulesAttrLink::getRulesId, param.getId()));
 
         List<PtlAgreementUndwrtRulesAttr> attrList = undwrtRulesAttrList;
         //再添加属性值
@@ -353,7 +459,7 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
             }
             costsAttrLink.add(link);
         });
-        agreementUndwrtRulesAttrLinkService.saveBatch(costsAttrLink);
+        mergeAttrLinks(oldLinks, costsAttrLink);
         rules.setStartTime(param.getStartTime());
         rules.setEndTime(param.getEndTime());
         rules.setRuleDescription(buildDesc(costsAttrLink, attrList));
@@ -554,6 +660,7 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
                     if (null != link.getMin()) {
                         attr.setId(link.getId());
                         attr.setMinArray(link.getMin().split(","));
+                        attr.setMin(link.getMin());
                         attr.setMax(link.getMax());
                         attr.setOperator(link.getOperator());
                     }
@@ -577,10 +684,30 @@ public class PtlAgreementUndwrtRulesServiceImpl extends ServiceImpl<PtlAgreement
 
     @Override
     public boolean deleteById(String id) {
+        // 查询当前规则的parentId
+        PtlAgreementUndwrtRules currentRule = baseMapper.selectById(id);
+        if (currentRule == null) {
+            return false;
+        }
+        // 收集需要删除的规则ID(同一parentId下的所有规则)
+        List<String> deleteRuleIds = new ArrayList<>();
+        deleteRuleIds.add(id);
+        if (currentRule.getParentId() != null && !currentRule.getParentId().isEmpty()) {
+            List<AgreementRulesVo> siblingRules = baseMapper.queryListByParentId(currentRule.getParentId());
+            if (CollUtil.isNotEmpty(siblingRules)) {
+                for (AgreementRulesVo vo : siblingRules) {
+                    if (!id.equals(vo.getId())) {
+                        deleteRuleIds.add(vo.getId());
+                    }
+                }
+            }
+        }
+        // 删除所有关联的attr_link
         agreementUndwrtRulesAttrLinkService.remove(
                 new LambdaQueryWrapper<PtlAgreementUndwrtRulesAttrLink>()
-                        .eq(PtlAgreementUndwrtRulesAttrLink::getRulesId, id));
-        return baseMapper.deleteById(id) > 0;
+                        .in(PtlAgreementUndwrtRulesAttrLink::getRulesId, deleteRuleIds));
+        // 批量删除规则
+        return baseMapper.deleteBatchIds(deleteRuleIds) > 0;
     }
 
     /**

+ 80 - 9
tenant/organization/src/main/java/com/jzg/organization/service/impl/ReceivableServiceImpl.java

@@ -793,6 +793,17 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             return resultList;
         }
 
+        // 查询当前公司下所有的子公司
+        if (StrUtil.isNotBlank(settlementReportQueryVo.getCompanyId())){
+            // 将全量数据按照 parentId 进行分组,key 是 parentId,value 是该 parentId 下的所有公司列表
+            Map<String, List<EsmInsCompany>> parentGroupMap = companyMap.values().stream()
+                    .filter(c -> c.getParentId() != null)
+                    .collect(Collectors.groupingBy(EsmInsCompany::getParentId));
+            List<String> allChildIdspOtimized = getAllChildIdsOptimized(settlementReportQueryVo.getCompanyId(), parentGroupMap);
+            allChildIdspOtimized.add(settlementReportQueryVo.getCompanyId());
+            settlementReportQueryVo.setCompanyIdList(allChildIdspOtimized);
+        }
+
         // 2. 查询跟单主数据并分组聚合
         List<FollowCompanyFeeVO> originalFollowList = insFeeFollowOrderMapper.selectFollowCompanySettlementReport(settlementReportQueryVo);
         if (CollUtil.isNotEmpty(originalFollowList)) {
@@ -928,6 +939,15 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                     .map(InsPlyIncomeInvoiceSettlement::getActualReceivedAmount)
                     .reduce(BigDecimal.ZERO, BigDecimal::add);
             vo.setTotalSettlementAmount(totalSettlementAmount);
+
+            // 回款差额
+            BigDecimal totalPaymentDifference = settlementIds.stream()
+                    .map(settlementMap::get)
+                    .filter(Objects::nonNull)
+                    .map(InsPlyIncomeInvoiceSettlement::getSettlementPaymentDifference)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            vo.setTotalPaymentDifference(totalPaymentDifference);
+
             // 设置未结算总金额,获取所有ins_fee_follow_order数据,只有所以的都结算了,才能算已结算
             List<InsFeeFollowOrder> insFeeFollowOrderList = followOrderMap.values().stream().filter(insFeeFollowOrder -> insFeeFollowOrder.getYear().toString().equals(year) && insFeeFollowOrder.getMonth().toString().equals(month) && insFeeFollowOrder.getPartnerCompanyId().equals(partnerCompanyId) && insFeeFollowOrder.getInvoiceType().equals(invoiceType)).toList();
             if (insFeeFollowOrderList.size() == insFeeFollowOrderList.stream().filter(insFeeFollowOrder -> SettlementIdentificationEnum.SETTLED.getCode().equals(insFeeFollowOrder.getSettlementIdentification())).count()){
@@ -991,7 +1011,7 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
     private List<InsPlyIncomeDto> queryFollowIncomeData(SettlementReportQueryVo queryVo) {
         QueryFollowIncomeVo incomeVo = QueryFollowIncomeVo.builder()
                 .systemCode(baseController.getSystemCode())
-                .companyId(queryVo.getCompanyId())
+                .companyIdList(queryVo.getCompanyIdList())
                 .startTime(queryVo.getStartTime()).endTime(queryVo.getEndTime())
                 .signingStartTime(queryVo.getSigningStartTime()).signingEndTime(queryVo.getSigningEndTime())
                 .build();
@@ -1363,9 +1383,13 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         records.forEach(insPlyIncome -> {
             if(StrUtil.isNotEmpty(insPlyIncome.getPartnerCompanyId())){
                 insPlyIncome.setPartnerCompanyName(allCompanyHierarchyPaths.getOrDefault(insPlyIncome.getPartnerCompanyId(),insPlyIncome.getPartnerCompanyId()));
+                if(StrUtil.isNotEmpty(insPlyIncome.getPartnerCompanyName())){
+                    String[] split = insPlyIncome.getPartnerCompanyName().split("/");
+                    if(split.length > 0){
+                        insPlyIncome.setPartnerCompanySimplyName(split[split.length-1]);
+                    }
+                }
             }
-
-
             if("0".equals(insPlyIncome.getSettlementStatus())){
                 insPlyIncome.setSettlementStatusName("未结算");
             }else if("1".equals(insPlyIncome.getSettlementStatus())){
@@ -1730,7 +1754,13 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             InsPlyIncomeInvoice invoice = new InsPlyIncomeInvoice();
             BeanUtils.copyProperties(invoicingVo, invoice);
             invoice.setId(IdGenerate.nextId());
+
+//            String incomeId = invoicingVo.getIncomeIds().get(0);
+
+            // 这里的公司应该是支公司的公司
             invoice.setCompanyId(invoicingVo.getCompanyId());
+
+            
             invoice.setInvoiceType(invoicingVo.getInvoiceType());
             //  开票类型  1、手续费  2、跟单费  3、驾意险手续费 4、驾意险跟单费 5、平台应收-车险 6、平台应收-非车险
             if("1".equals(invoicingVo.getInvoiceType()) || "2".equals(invoicingVo.getInvoiceType())){
@@ -4135,9 +4165,9 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
             // 校验:累计开票金额 <= 对账金额
             // 假设 item.getUninvoiced() 是未开票金额,需要从数据库查历史已开票金额
             // 这里简化逻辑:如果本次开票总额大于对账金额,则报错
-            if (totalInvoiceAmount.compareTo(reconciliationAmount) > 0) {
-                throw new SystemException("开票金额不可大于对账金额[对账金额:" + reconciliationAmount + "]");
-            }
+//            if (totalInvoiceAmount.compareTo(reconciliationAmount) > 0) {
+//                throw new SystemException("开票金额不可大于对账金额[对账金额:" + reconciliationAmount + "]");
+//            }
 
             // 构建跟单订单明细
             InsFeeFollowOrder order = new InsFeeFollowOrder();
@@ -4157,6 +4187,14 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                 order.setUninvoiced(receivable.subtract(invoicedThisTime));
                 order.setInvoicedAmountTime(invoicedThisTime);
                 order.setInvoiced(invoicedThisTime); // 假设已开票字段需要累加
+            }else if ("1".equals(vo.getSelectFlag())){
+                // 多条处理逻辑
+                BigDecimal reconciliation = item.getReconciliationAmount();
+
+                // 更新未开票金额 = 应收 - 本次开票
+                order.setUninvoiced(BigDecimal.ZERO);
+                order.setInvoicedAmountTime(reconciliation);
+                order.setInvoiced(reconciliation); // 假设已开票字段需要累加
             }
 
             // 设置新增字段 (保存对账信息)
@@ -4837,6 +4875,13 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         }
         invoiceRecordQueryVo.setSystemCode(baseController.getSystemCode());
         Page<InvoiceRecordResult> invoiceRecordList = null;
+
+        // add by lipf 2026年7月31日09:36:12 支持通过子公司查询总公司的数据
+        String companyId = invoiceRecordQueryVo.getCompanyId();
+        if(StrUtil.isNotEmpty(companyId)){
+            HttpResult<List<String>> companyIds =  esmInsCompanyClient.queryRelatedCompanyIds(companyId);
+            invoiceRecordQueryVo.setCompanyIds(companyIds.getData());
+        }
         if (invoiceRecordQueryVo.getInvoiceTypes().contains("2") || invoiceRecordQueryVo.getInvoiceTypes().contains("4")){
             invoiceRecordList = baseMapper.getFollowInvoiceRecordList(invoiceRecordQueryVo.getPage(), invoiceRecordQueryVo);
         }else if(invoiceRecordQueryVo.getInvoiceTypes().contains("1") || invoiceRecordQueryVo.getInvoiceTypes().contains("3")){
@@ -4884,6 +4929,11 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                     log.error("根据保险公司序号[{}]没有找到保险公司",action.getCompanyId());
                 }
                 action.setCompanyAllName(companyAllName);
+                if(StrUtil.isNotEmpty(companyAllName)){
+                    String parentCompanyName = companyAllName.split("/")[0];
+                    action.setParentCompanyName(parentCompanyName);
+                }
+
                 action.setSettlementStatus(settlementStatusName);
 
                 // 回款差额
@@ -4892,14 +4942,22 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
                 if (invoiceRecordQueryVo.getInvoiceTypes().contains(InvoiceTypeEnum.FEE_2.getCode())) {
                     LambdaQueryWrapper<InsFeeFollowOrder> insFeeFollowOrderLambdaQueryWrapper = new LambdaQueryWrapper<>();
                     insFeeFollowOrderLambdaQueryWrapper.eq(InsFeeFollowOrder::getYear, action.getYear());
-                    insFeeFollowOrderLambdaQueryWrapper.eq(InsFeeFollowOrder::getMonth, action.getMonth());
+                    List<String> monthList;
+                    String monthStr = action.getMonth();
+                    String searchStr = ",";
+                    if (StrUtil.contains(monthStr, searchStr)) {
+                        monthList = Arrays.asList(monthStr.split(searchStr));
+                    } else {
+                        monthList = Collections.singletonList(monthStr);
+                    }
+                    insFeeFollowOrderLambdaQueryWrapper.in(InsFeeFollowOrder::getMonth, monthList);
                     insFeeFollowOrderLambdaQueryWrapper.eq(InsFeeFollowOrder::getPartnerCompanyId, action.getPartnerCompanyId());
                     insFeeFollowOrderLambdaQueryWrapper.in(InsFeeFollowOrder::getInvoiceType, action.getInvoiceType());
                     List<InsFeeFollowOrder> insFeeFollowOrders = insFeeFollowOrderMapper.selectList(insFeeFollowOrderLambdaQueryWrapper);
                     if (CollUtil.isNotEmpty(insFeeFollowOrders)){
-                        InsFeeFollowOrder insFeeFollowOrder = insFeeFollowOrders.stream().findAny().get();
+                        BigDecimal bigDecimal = insFeeFollowOrders.stream().map(InsFeeFollowOrder::getReceivablePremium).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
                         // 开票金额
-                        action.setReceivableAmount(insFeeFollowOrder.getReceivablePremium().toString());
+                        action.setReceivableAmount(bigDecimal.toString());
                     }
                 }else if (invoiceRecordQueryVo.getInvoiceTypes().contains(InvoiceTypeEnum.FEE_1.getCode())){
                     action.setReceivableAmount(action.getReceivableSupervisePremium().subtract(action.getOverinflatedAmount()).toString());
@@ -6514,5 +6572,18 @@ public class ReceivableServiceImpl extends ServiceImpl<ReceivableMapper, InsPlyI
         LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);
         return date.atTime(23, 59, 59, 999999999);
     }
+
+    // 递归获取所有子孙ID
+    private List<String> getAllChildIdsOptimized(String parentId, Map<String, List<EsmInsCompany>> parentGroupMap) {
+        List<String> result = new ArrayList<>();
+        // 直接通过 parentId 获取子节点列表,无需遍历全量数据
+        List<EsmInsCompany> children = parentGroupMap.getOrDefault(parentId, Collections.emptyList());
+
+        for (EsmInsCompany company : children) {
+            result.add(company.getId());
+            result.addAll(getAllChildIdsOptimized(company.getId(), parentGroupMap));
+        }
+        return result;
+    }
 }
 

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

@@ -74,9 +74,9 @@
                     #{item}
                 </foreach>
             </if>
-            <if test="query.companyId != null and query.companyId != ''" >
+            <!--<if test="query.companyId != null and query.companyId != ''" >
                 AND ffo.partner_company_id = #{query.companyId}
-            </if>
+            </if>-->
             -- 跟单订单创建时间范围
             <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
                 AND ffo.create_time BETWEEN #{query.startTime} AND #{query.endTime}

+ 1 - 1
tenant/organization/src/main/resources/mapper/PtlAgreementUndwrtRulesAttrLinkMapper.xml

@@ -22,7 +22,7 @@
     <sql id="Base_Column_List">
         pl.id,pl.rules_id,
         pl.attr_code,pl.min,pl.operator,
-        pl.max,pl.create_time,
+        pl.max,pl.min,pl.create_time,
         pl.create_by,pl.update_time,pl.update_by,
         pl.is_delete
     </sql>

+ 17 - 4
tenant/organization/src/main/resources/mapper/ReceivableMapper.xml

@@ -165,6 +165,7 @@
         pa.id AS agreement_id,
         pa.agreement_name,
         pa.agreement_type,
+        pa.partner_company_id,
         io.product_id,
         io.product_name,
         io.pay_time,
@@ -1395,7 +1396,16 @@
         eic.`name`
         FROM
         ins_ply_income ipi
-        LEFT JOIN esm_ins_company eic ON ipi.company_id = eic.id AND eic.is_delete = 0
+        left join ins_orders io
+        on
+        ipi.order_no = io.id
+        left join ptl_agreement pa
+        on
+        io.agreement_id = pa.id
+        LEFT JOIN esm_ins_company eic
+        ON
+        pa.partner_company_id = eic.id
+        AND eic.is_delete = 0
         <where>
             ipi.is_delete = 0
             AND ipi.id IN
@@ -1526,8 +1536,11 @@
             <if test="invoiceRecordQueryVo.recordId != null and invoiceRecordQueryVo.recordId != ''">
                 AND ipii.id = #{invoiceRecordQueryVo.recordId}
             </if>
-            <if test="invoiceRecordQueryVo.companyId != null and invoiceRecordQueryVo.companyId != ''">
-                AND ipii.company_id = #{invoiceRecordQueryVo.companyId}
+            <if test="invoiceRecordQueryVo.companyIds != null and invoiceRecordQueryVo.companyIds.size() > 0">
+                AND ipii.company_id IN
+                <foreach collection="invoiceRecordQueryVo.companyIds" open="(" close=")" item="companyId" separator=",">
+                    #{companyId}
+                </foreach>
             </if>
             <if test="invoiceRecordQueryVo.invoiceNo != null and invoiceRecordQueryVo.invoiceNo != ''">
                 AND ipii.invoice_no like concat('%',#{invoiceRecordQueryVo.invoiceNo},'%')
@@ -2126,7 +2139,7 @@
                 AND a.create_time between #{query.startTime} and #{query.endTime}
             </if>
             <if test="query.companyIdList != null and query.companyIdList.size() > 0" >
-                AND a.company_id in
+                AND b.partner_company_id in
                 <foreach collection="query.companyIdList" item="item" open="(" separator="," close=")">
                     #{item}
                 </foreach>