Переглянути джерело

批量修改协议费用有效期;自选方案默认给最小保额;费用规则校验修正

lixiaolong 1 місяць тому
батько
коміт
07a175a1a7

+ 46 - 0
commons/src/main/java/com/jzg/commons/entity/dto/PtlAgreementCostBatchUpdateValidDateParam.java

@@ -0,0 +1,46 @@
+package com.jzg.commons.entity.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 批量修改协议费用有效期参数
+ */
+@Data
+@Schema(description = "批量修改协议费用有效期参数")
+public class PtlAgreementCostBatchUpdateValidDateParam implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "协议费用ID列表(勾选的费用ID,优先级最高)")
+    private List<String> costIds;
+
+    @Schema(description = "协议ID(与报价类型组合筛选)")
+    private String ptlAgreementId;
+
+    @Schema(description = "承保规则ID(与协议ID、报价类型组合筛选)")
+    private String coverRuleId;
+
+    @Schema(description = "报价类型列表(如:0330=单交, 034001=单商, 034002=单三, 0330034002=交三, 0330034001=交商)")
+    private String costType;
+
+    @Schema(description = "生效时间(起)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "生效时间不能为空")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date effectiveTime;
+
+    @Schema(description = "失效时间(止)", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotNull(message = "失效时间不能为空")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date failureTime;
+
+}

+ 85 - 8
tenant/insurance/quotation-summary/src/main/java/com/jzg/quotation/summary/aop/FactorMatch.java

@@ -274,9 +274,18 @@ public class FactorMatch {
 
 
     private static boolean checkBoxEqual(PtlAgreementCostRule ptlAgreementCostRule, String value) {
+        if (ptlAgreementCostRule.getMin() == null || value == null) {
+            return false;
+        }
         String[] split = ptlAgreementCostRule.getMin().split(",");
         for (String sp : split) {
-            if (sp.equals(value)) {
+            if (sp.trim().equals(value.trim())) {
+                return true;
+            }
+            // 顺带支持是/否归一化
+            String n1 = normalizeYesNo(sp.trim());
+            String n2 = normalizeYesNo(value.trim());
+            if (!n1.equals(sp.trim()) && !n2.equals(value.trim()) && n1.equals(n2)) {
                 return true;
             }
         }
@@ -347,8 +356,21 @@ public class FactorMatch {
     }
 
     private static boolean selectEqual(PtlAgreementCostRule ptlAgreementCostRule, String value) {
-        if (ptlAgreementCostRule.getMin() != null && ptlAgreementCostRule.getMin().contains(value)) {
-            return true;
+        if (ptlAgreementCostRule.getMin() == null || value == null) {
+            return false;
+        }
+        // 修复:select 支持多选逗号分隔,所以正确做法是 split 后逐个 equals
+        String[] options = ptlAgreementCostRule.getMin().split(",");
+        for (String opt : options) {
+            if (opt.trim().equals(value.trim())) {
+                return true;
+            }
+            // 顺带支持是/否归一化
+            String n1 = normalizeYesNo(opt.trim());
+            String n2 = normalizeYesNo(value.trim());
+            if (!n1.equals(opt.trim()) && !n2.equals(value.trim()) && n1.equals(n2)) {
+                return true;
+            }
         }
         return false;
     }
@@ -358,15 +380,70 @@ public class FactorMatch {
         if ("NewEnergy".equals(ptlAgreementCostRule.getAttrCode())) {
             // 是否是新能源车
             boolean newEnergy = EnergyTypeCode.isNewEnergy(value);
-            if (newEnergy && ptlAgreementCostRule.getMin().equals("1")) {
+            if (newEnergy && "1".equals(normalizeYesNo(ptlAgreementCostRule.getMin()))) {
                 return true;
-            } else if (!newEnergy && ptlAgreementCostRule.getMin().equals("0")) {
+            } else if (!newEnergy && "0".equals(normalizeYesNo(ptlAgreementCostRule.getMin()))) {
                 return true;
             }
-        } else if (ptlAgreementCostRule.getMin().contains(value)) {
-            return true;
+            return false;
         }
-        return false;
+
+        // ========== 修复:归一化 是/否 类的 value ==========
+        String ruleValue = (ptlAgreementCostRule.getMin() != null) ? ptlAgreementCostRule.getMin() : ptlAgreementCostRule.getMax();
+        String normalizedRule = normalizeYesNo(ruleValue);
+        String normalizedValue = normalizeYesNo(value);
+
+        String operator = ptlAgreementCostRule.getOperator();
+        if (operator == null) operator = "1"; // 默认 等于
+
+        switch (operator) {
+            case "1": // 等于(默认)
+                // 修复1:先归一化后比较(解决 N/0、Y/1 不一致的问题)
+                if (normalizedRule != null && normalizedValue != null
+                        && !normalizedRule.equals(ruleValue) && !normalizedValue.equals(value)) {
+                    // 两个都经过归一化翻译了,直接比归一化后的值
+                    return normalizedRule.equals(normalizedValue);
+                }
+                // 修复2:用 equals 代替 contains(避免 "10".contains("0") 的误判)
+                return (ruleValue != null && ruleValue.equals(value))
+                        || (normalizedRule != null && normalizedRule.equals(normalizedValue));
+
+            case "2": // 不等于
+                if (normalizedRule != null && normalizedValue != null
+                        && !normalizedRule.equals(ruleValue) && !normalizedValue.equals(value)) {
+                    return !normalizedRule.equals(normalizedValue);
+                }
+                return ruleValue == null || !ruleValue.equals(value);
+
+            case "3": case "4": case "5": // 其他运算符(radio 一般用不上,兜底)
+                return inputNumberEqual(ptlAgreementCostRule, value);
+
+            default:
+                return (ruleValue != null && ruleValue.equals(value));
+        }
+    }
+
+    /**
+     * 归一化"是/否"类的值,把各种表达方式统一成 1/0
+     * 是: "1", "Y", "y", "是", "true", "TRUE", "True" -> "1"
+     * 否: "0", "N", "n", "否", "false", "FALSE", "False" -> "0"
+     * 其他值原样返回
+     */
+    private static String normalizeYesNo(String value) {
+        if (value == null) return null;
+        String v = value.trim();
+        if (v.isEmpty()) return v;
+        // 是否的"是"
+        if ("1".equals(v) || "Y".equalsIgnoreCase(v) || "true".equalsIgnoreCase(v)
+                || "是".equals(v) || "T".equalsIgnoreCase(v) || "YES".equalsIgnoreCase(v)) {
+            return "1";
+        }
+        // 是否的"否"
+        if ("0".equals(v) || "N".equalsIgnoreCase(v) || "false".equalsIgnoreCase(v)
+                || "否".equals(v) || "F".equalsIgnoreCase(v) || "NO".equalsIgnoreCase(v)) {
+            return "0";
+        }
+        return v;
     }
 
     public static boolean dateTimeEqual(PtlAgreementCostRule ptlAgreementCostRule, String value){

+ 16 - 0
tenant/organization/src/main/java/com/jzg/organization/controller/AgreementController.java

@@ -14,6 +14,7 @@ import com.jzg.commons.entity.vo.AgreementVo;
 import com.jzg.commons.entity.vo.UpAndDownVo;
 import com.jzg.commons.util.AssertionUtils;
 import com.jzg.organization.mapper.PtlAgreementMapper;
+import com.jzg.organization.service.PtlAgreementCostService;
 import com.jzg.organization.service.PtlAgreementDeptService;
 import com.jzg.organization.service.PtlAgreementService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -43,6 +44,9 @@ public class AgreementController extends BaseController {
     @Autowired
     private PtlAgreementDeptService agreementDeptService;
 
+    @Autowired
+    private PtlAgreementCostService ptlAgreementCostService;
+
     @Autowired
     BaseController baseController;
 
@@ -211,6 +215,18 @@ public class AgreementController extends BaseController {
         return HttpResult.ok("复制成功");
     }
 
+    /**
+     * 批量修改协议费用有效期
+     * @param param 参数
+     * @return HttpResult
+     */
+    @Operation(summary = "批量修改协议费用有效期(按报价类型筛选)")
+    @PostMapping("/agreementCostBatchUpdateValidDate")
+    public HttpResult<String> agreementCostBatchUpdateValidDate(
+            @Validated @RequestBody PtlAgreementCostBatchUpdateValidDateParam param) {
+        return ptlAgreementCostService.batchUpdateValidDate(param);
+    }
+
     /**
      * 外部协议添加
      * @param param

+ 5 - 0
tenant/organization/src/main/java/com/jzg/organization/service/PtlAgreementCostService.java

@@ -64,4 +64,9 @@ public interface PtlAgreementCostService extends IService<PtlAgreementCost> {
      */
     Boolean costCopy(PtlAgreementCostCopyParam costCopyParam);
 
+    /**
+     * 批量修改协议费用有效期
+     */
+    HttpResult<String> batchUpdateValidDate(PtlAgreementCostBatchUpdateValidDateParam param);
+
 }

+ 59 - 0
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlAgreementCostServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 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.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.jzg.commons.constants.Constants;
@@ -67,6 +68,9 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
     @Resource
     private PtlAgreementUndwrtRulesAttrService agreementUndwrtRulesAttrService;
 
+    @Autowired
+    private PtlAgreementCostTypeService ptlAgreementCostTypeService;
+
     @Autowired
     RedissonClient redissonClient;
 
@@ -441,5 +445,60 @@ public class PtlAgreementCostServiceImpl extends ServiceImpl<PtlAgreementCostMap
         return true;
     }
 
+    @Override
+    public HttpResult<String> batchUpdateValidDate(PtlAgreementCostBatchUpdateValidDateParam param) {
+        // 1. 校验时间
+        if (param.getEffectiveTime() == null || param.getFailureTime() == null) {
+            return HttpResult.error("生效时间和失效时间不能为空");
+        }
+        if (param.getFailureTime().before(param.getEffectiveTime())
+                || param.getFailureTime().equals(param.getEffectiveTime())) {
+            return HttpResult.error("失效时间必须晚于生效时间");
+        }
+
+        List<String> finalCostIds;
+
+        // 2. 优先使用直接传入的 costIds
+        if (param.getCostIds() != null && !param.getCostIds().isEmpty()) {
+            finalCostIds = param.getCostIds();
+        } else if (param.getPtlAgreementId() != null && !param.getPtlAgreementId().isEmpty()) {
+            // 3. 否则根据协议ID + 承保规则ID + 报价类型筛选
+            LambdaQueryWrapper<PtlAgreementCost> costWrapper = new LambdaQueryWrapper<>();
+            costWrapper.eq(PtlAgreementCost::getPtlAgreementId, param.getPtlAgreementId());
+            if (param.getCoverRuleId() != null && !param.getCoverRuleId().isEmpty()) {
+                costWrapper.eq(PtlAgreementCost::getCoverRuleId, param.getCoverRuleId());
+            }
+            List<PtlAgreementCost> costs = this.list(costWrapper);
+            if (costs.isEmpty()) {
+                return HttpResult.ok("没有找到匹配的费用记录");
+            }
+            List<String> allCostIds = costs.stream().map(PtlAgreementCost::getId).toList();
+
+            // 如果指定了报价类型,进一步筛选
+            if (param.getCostType() != null && !param.getCostType().isEmpty()) {
+                LambdaQueryWrapper<PtlAgreementCostType> typeWrapper = new LambdaQueryWrapper<>();
+                typeWrapper.in(PtlAgreementCostType::getPtlAgreementCostId, allCostIds);
+                typeWrapper.eq(PtlAgreementCostType::getCostType, param.getCostType());
+                List<PtlAgreementCostType> types = ptlAgreementCostTypeService.list(typeWrapper);
+                finalCostIds = types.stream().map(PtlAgreementCostType::getPtlAgreementCostId).distinct().toList();
+            } else {
+                finalCostIds = allCostIds;
+            }
+        } else {
+            return HttpResult.error("请勾选要修改的费用,或传入协议ID进行筛选");
+        }
+
+        // 4. 批量更新有效期
+        LambdaUpdateWrapper<PtlAgreementCost> updateWrapper = new LambdaUpdateWrapper<>();
+        updateWrapper.in(PtlAgreementCost::getId, finalCostIds);
+        updateWrapper.set(PtlAgreementCost::getEffectiveTime, param.getEffectiveTime());
+        updateWrapper.set(PtlAgreementCost::getFailureTime, param.getFailureTime());
+        boolean success = this.update(updateWrapper);
+
+        return success
+                ? HttpResult.ok("批量修改成功,共修改 " + finalCostIds.size() + " 条记录")
+                : HttpResult.error("批量修改失败");
+    }
+
 
 }

+ 35 - 2
tenant/organization/src/main/java/com/jzg/organization/service/impl/PtlSchemeServiceImpl.java

@@ -50,6 +50,7 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -694,10 +695,42 @@ public class PtlSchemeServiceImpl extends ServiceImpl<PtlSchemeMapper, PtlScheme
             });
         });
 
-        //自选方案
+        //自选方案 - 默认保额选最小
         SchemeResultVo.SchemeVo opSchemeVo = schemeInsuranceInfo.stream().filter(x -> !TextUtils.isEmpty(x.getSchemeType()) && x.getSchemeType().equals("2")).findFirst().orElse(null);
         if (Objects.nonNull(opSchemeVo)) {
-            schemeResultVo.setOptionalScheme(opSchemeVo.getInfos().get(0));
+            SchemeResultVo.SchemeInfoVo optionalSchemeInfo = opSchemeVo.getInfos().get(0);
+            if (optionalSchemeInfo.getKinds() != null) {
+                optionalSchemeInfo.getKinds().forEach(kind -> {
+                    if (!kind.getOptions().isEmpty()) {
+                        BigDecimal minVal = null;
+                        String minValueStr = kind.getOptions().get(0).getValue();
+                        for (SchemeResultVo.Option opt : kind.getOptions()) {
+                            String label = opt.getLabel();
+                            String value = opt.getValue();
+                            // 跳过"不投保"、"投保"、"0"等
+                            if ((label != null && (label.contains("不投") || label.contains("投保")))
+                                    || "0".equals(value) || "不投保".equals(value) || value == null || value.isEmpty()) {
+                                continue;
+                            }
+                            try {
+                                String clean = value.replaceAll("[^0-9.]", "");
+                                if (!clean.isEmpty()) {
+                                    BigDecimal num = new BigDecimal(clean);
+                                    if (minVal == null || num.compareTo(minVal) < 0) {
+                                        minVal = num;
+                                        minValueStr = value;
+                                    }
+                                }
+                            } catch (Exception ignored) {}
+                        }
+                        kind.setAmount(minValueStr);
+                        kind.setUnitAmount(minValueStr);
+                        kind.setServiceTimes(minValueStr);
+                        kind.setDeductibleRate(minValueStr);
+                    }
+                });
+            }
+            schemeResultVo.setOptionalScheme(optionalSchemeInfo);
         }
 
         //排除交强险的险种